home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / ada / atutr202.zip / ada_tutr.dat < prev    next >
Text File  |  1992-09-04  |  308KB  |  1 lines

  1.  120 564  @!  EN  IJ  LA  Y_  \?  e1  j!  n<  t#  y*  }X !"U !*, !.^ !2P !8& !=T !A9 !J& !\' !nC !~Y ",\ "3Q "E8Q"W8 "^6 "`G "f_ "j%Q"oX #!- #(-Q#/6 #2- #6& #:, #A! #PF #`/ #o6 #}3Q$*M $.M $2* $5^Q$:5 $=] $AG $EF $IZ $U" $]& $l(Q$|+ %!B %'[ %+< %.M %2[ %89 %<A %KQ %Y\ %iI %|0Q&,> &4" &;N &BR &IJ &RK &YB &eJ &wPQ')4 '+A '0\ '6/ 'G_A'X0 'i4 't. '{/ (*W (A@Q(WN (Z? (\D (_* (f! (t, )$0Q)4X );+ )@F )H) )UN )c6 )xBQ*([ *-` *6- *;T *AZ *G` *W^ *aX *tGQ+(1 ++P +.V +1P +AH +Q7Q+^: +dR +fY +j- +lO +o, +rT +u1 +|( ,/8 ,C!Q,LK ,PN ,SR ,X% ,^J ,hO ,v. -*'Q-8[ -?6 -C, -FT -T; -e& -s(Q-~- .&< .," .1+ .7T .=@ .BD .L) .R; .cLQ.wW .|M /"T /(9 /0, />! /KIQ/UM /Z^ /_4 /bP /gJ /x<Q0#+ 0,1 06. 0>U 0G& 0T' 0^8A0l' 1!I 10O 1=! 1IA 1S] 1]< 1kV 1rM 2 F 21QQ2=1 2F) 2HQ 2K< 2N> 2Q% 2d* 2sG 3%9 36=Q3FT 3QR 3]& 3f5 3pP 3{Q 4*\ 4:K 4K> 4]8Q4c* 4j" 4oQ 4u# 4|] 50: 5A[ 5XMQ5c1 5j9 5y8 6%9 6-G 65D 6@- 6G- 6OV 6ZYA6l] 6zP 7+W 78Q 7L! 7X9 7f_ 7mV 7|' 8,Y 8;]Q8L) 8V1 8`F 8jP 8u^ 9#T 96] 9F:A9TT 9dG 9k) 9x5 :&V :-M :9W :E8 :K, :T8Q:d[ :jA :tO :}? ;$H ;*) ;2- ;8- ;I& ;YMQ;f? ;j@ ;pF ;tI ;y. <(R <3N <DA <N&Q<\7 <bU <iW <pP <~F =1& =:TQ=KA =UN =aE =kB =u+ >!D >1UQ>A4 >H" >NO >S; >fN >s* >}J ?.*Q?>Y ?B9 ?EV ?I2 ?U+ ?d[ ?p* ?|=Q@+? @0E @7Q @>B @QT @a9 @lDQ@u` A"D A,= A5X A<Q AJ] A]Z ArB B!TQB-P B3? B90 B>U BP] BZ%QBhU BmZ Bu@ B{> C!J C&V C.3 C@^ CN< C\(QCbT CmC Cp[ Ct6 Cw& D)R D:6 DC?QD[B D`O Dd% Dg= DjU DmH Dq! D|! E%5 E<>QEN" ETX EZI E`& ErR F)I F9Y FE<QFPA FST FVA FYL F\WAF_4 FuE F}$ G$> G0X G<Q GI6 GRB GY9 Gg7 H 0 H2_QH<" HCR HMW HVR H`+ HiS Hx^ I&E I4_QICK IJO IS. I[> Id> Il< Iz> J#UQJ/* J:C JEJ JP5 JX[ J`1 JkGAJvE K'4 K22 K>J KE+ KL" KZ: Ki[ K~T L($QL6I L:. L>D LA; LD% LQ3 L`+ Lm'QLv[ M U M)Y M40 ME/ MRJ Ma/QMlJ Mq. Mu9 MyR M~& N#7 N6] NNK NZ/ Nm]QN|J O$- O,W O31 O9J OIX OXY Og: Ot+ P&KQP2I P6" P:# P=U PL= P_B Pg7 PyCQQ/4 Q27 Q8P Q<9 Q?A QSF QiN QvB R#] R.` R?L RJ. RRK                                                                                                                        {@-\@T`{@-\ ~@P\ `{@-\ ~@'^C O N G R A T U L A T I O N S !~@(\ `{@-\ ~@P\ `{@-\@T`{{{@&^You've successfully completed ADA-TUTR, the Interactive Ada Tutor.`{{{@1Your comments and suggestions are encouraged.{@>Please send them to:{{@+Software Innovations Technology, Attention: John J. Herro{@01083 Mandarin Drive NE, Palm Bay, FL 32905-4706{{{@@Have a good day!{{{[]{{@:Thank you for using^ADA-TUTR`.{{{@2Please send your comments and suggestions to{{@+Software Innovations Technology, Attention: John J. Herro{@01083 Mandarin Drive NE, Palm Bay, FL 32905-4706{{{@0I hope to see you again soon.  Have a good day!{{{{[]{{{@7The current screen number is$.{{@2You're about# percent through the course.{{{{{@7Do you want to exit^ADA-TUTR~now?{}Please press Y for yes or N for no.[Y102N108B108 108#105M106]~@#\@f`{@$\ ~@b\ `{@$\ ~@7W E L C O M E@#T O@8\ `{@$\ ~@b\ `{@$\ ~@8^A D A - T U T R~@9\ `{@$\ ~@b\ `{@$\ ~@(T H E@#I N T E R A C T I V E@#A D A@#T U T O R@)\ `{@$\ ~@b\ `{@$\@7by John J. Herro, Ph.D.@8`{{@$Software Innovations Technology@1Serial #  31398{@(1083 Mandarin Drive NE@7Version  2.02{@'Palm Bay, FL  32905-4706@84-SEP-1992{@,(407) 951-0233@2Copyright 1988-92 John J. Herro{{@$Shareware: Try^ADA-TUTR~free.  To use it after the free trial, individ-{@$uals must register and organizations must buy a license.  Both are very{@$inexpensive, and give many benefits.  See page 2 of PRINT.ME for infor-{@$mation.  Whether or not you use^ADA-TUTR~and register or buy a license,{@$please copy the complete program and give unmodified copies to others!{{@9Have you used^ADA-TUTR~before?{}@(Please press Y for yes or N for no.  You need not hit ENTER.[Y107N120]{{@3What screen number would you like to see?{{@'(If you don't know, type 106 and I'll take you to the main menu.){{{Please type the number and press ENTER:{[#]@CMAIN MENU{{{%A~ Restart the Program.@1^G~ Records, Arrays, and Assignment 3{{%B~ Introduction@9^H~ Recursion and Assignment 4{{%C~ The Format of an Ada Program@)^I~ Subprograms and Packages{{%D~ Generic Instantiation and@,^J~ Additional Types, Exceptions,{@&Assignment 1@=TEXT_IO, and Assignment 5{{%E~ Simple Declarations and Simple@'^K~ Generics, Tasking, and Assignment 6{@&Attributes{@H^L~ Advanced Topics{%F~ Operators, Control Constructs, and{@&Assignment 2@6^X~ Exit the Program.{}Please press a letter.[A104B109C110D111E112F113G114H115I116J117K118L119]{{@@^WELCOME BACK!`{{{{@?Would you like to:{{{@2^1~ Resume where we left off?{{@2^2~ Go back to the last question?{{@2^3~ Go back to the last Outside Assignment?{{@2^4~ Go to the main menu?{{@2^5~ Go to a screen number of your choice?{}Please press 1, 2, 3, 4, or 5.[11002099309841065105 100B100#105M106]{{@?Would you like to:{{{@2^1~ Go back to where we were?{{@2^2~ Go back to the last question?{{@2^3~ Go back to the last Outside Assignment?{{@2^4~ Go to the main menu?{{@2^5~ Go to a screen number of your choice?{}Please press 1, 2, 3, 4, or 5.[11002099309841065105 100B100#105M106]@BINTRODUCTION{@FMENU{{{^A~ Welcome@>^E~ What is Ada?{{^B~ Printed Course Notes@1^F~ A Very Brief History of Ada{{^C~ Do I Need a Textbook for this@(^G~ What's a "Validated" Ada Compiler?{@&Course?{@I^M~ Go Back to the Main Menu.{^D~ Do I Need an Ada Compiler for{@&this Course?@7^X~ Exit the Program.{}Please press a letter.[A120B121C122D123E125F126G132M106]@:THE FORMAT OF AN ADA PROGRAM{@FMENU{{{@%^A~ Our First Ada Program@.^F~ Numbers{{@%^B~ Local Declarations@1^G~ Making the Dot Notation{@SAutomatic{@%^C~ Capitalization and Spacing{{@%^D~ Comments@;^M~ Go Back to the Main Menu.{{@%^E~ Identifiers@8^X~ Exit the Program.{}Please press a letter.[A139B141C152D154E155F163G164M106]@5GENERIC INSTANTIATION AND ASSIGNMENT 1{@FMENU{{{@1^A~ Displaying Integers{{@1^B~ Generic Instantiation{{@1^C~ Outside Assignment 1 -{@8Preparing to Run Ada on Your Computer{{@1^D~ The Ada Library{{{@1^M~ Go Back to the Main Menu.{{@1^X~ Exit the Program.{}Please press a letter.[A174B180C182D185M106]@3SIMPLE DECLARATIONS AND SIMPLE ATTRIBUTES{@FMENU{{{@9^A~ Variables and Constants{{@9^B~ Enumeration Types{{@9^C~ Subtypes{{@9^D~ Simple Attributes{{{@9^M~ Go Back to the Main Menu.{{@9^X~ Exit the Program.{}Please press a letter.[A192B198C207D209M106]@0OPERATORS, CONTROL CONSTRUCTS, AND ASSIGNMENT 2{@FMENU{{{@$^A~ Operators@6^H~ Labels and GOTOs{{@$^B~ Range Tests@4^I~ The CASE Construct{{@$^C~ The Short Circuit Forms@(^J~ Brief Overview of Functions{{@$^D~ The IF Block@3^K~ Outside Assignment 2 -{@NExercise in Enumeration Types{@$^E~ WHILE Loops{{@$^F~ FOR Loops@6^M~ Go Back to the Main Menu{{@$^G~ The EXIT Statement@-^X~ Exit the Program.{}Please press a letter.[A225B227C232D240E249F251G257H259I264J270K273M106]@7RECORDS, ARRAYS, AND ASSIGNMENT 3{@FMENU{{{@9^A~ Records{{@9^B~ Arrays{{@9^C~ Multidimensional Arrays{{@9^D~ Strings{{@9^E~ Array Operators{{@9^F~ Outside Assignment 3 -{@@Exercise in Records{{{@9^M~ Go Back to the Main Menu.{{@9^X~ Exit the Program.{}Please press a letter.[A281B289C301D308E320F322M106]@;RECURSION AND ASSIGNMENT 4{@FMENU{{{@8^A~ Recursion{{@8^B~ The Tower of Hanoi Problem{{@8^C~ Outside Assignment 4 -{@?Exercise in Recursion{{{@8^M~ Go Back to the Main Menu.{{@8^X~ Exit the Program.{}Please press a letter.[A329B336C341M106]@<SUBPROGRAMS AND PACKAGES{@FMENU{{{@4^A~ Procedures and Functions{{@4^B~ Default Parameters{{@4^C~ Packages{{@4^D~ Functions with Infix Notation{{@4^E~ Information Hiding: Private Types{{@4^F~ Type TEXT and Limited Private Types{{{@4^M~ Go Back to the Main Menu.{{@4^X~ Exit the Program.{}Please press a letter.[A346B358C365D373E381F396M106]@,ADDITIONAL TYPES, EXCEPTIONS, TEXT_IO, AND ASSIGNMENT 5{@FMENU{{{@4^A~ Access Types{{@4^B~ User Defined Types and Portability{{@4^C~ Derived Types{{@4^D~ Exceptions{{@4^E~ More About TEXT_IO{{@4^F~ Outside Assignment 5 -{@;Writing a Simple Line Editor{{{@4^M~ Go Back to the Main Menu.{{@4^X~ Exit the Program.{}Please press a letter.[A411B428C430D436E453F463M106]@6GENERICS, TASKING, AND ASSIGNMENT 6{@FMENU{{{@9^A~ Generics{{@9^B~ Tasking{{@9^C~ Outside Assignment 6 -{@@Exercise in Tasking{{{@9^M~ Go Back to the Main Menu.{{@9^X~ Exit the Program.{}Please press a letter.[A471B479C499M106]@@ADVANCED TOPICS{@FMENU{{{%A~ Renaming@=^H~ Subprogram Parameters with Generics{{%B~ Packages STANDARD and ASCII@*^I~ Representation Clauses and SYSTEM{{%C~ An Alternative to Infix Notation@%^J~ Unchecked Conversion and Unchecked{@ODeallocation{%D~ Record Discriminants and Record{@&Variants@:^K~ Pragmas{{%E~ Fixed Point and Universal Types@&^L~ Loose Ends and Pitfalls{{%F~ More Attributes@6^M~ Go Back to the Main Menu.{{%G~ SEQUENTIAL_IO and DIRECT_IO@*^X~ Exit the Program.{}Please press a letter.[A504B506C508D513E520F529G532H538I540J547K550L556M106]@)\@\`{@)\ ~@X\ `{@)\ ~@#^WELCOME TO ADA-TUTR, THE INTERACTIVE ADA TUTOR!~@$\ `{@)\ ~@X\ `{@)\@\`{{%ADA-TUTR~will make you an excellent Ada programmer in minimum time.  You should{be familiar with at least one other high-level language (Basic, Pascal, etc.){{You can study as long as you like.  Whenever you want to exit the program, just{type X.  (I'll ask you to confirm that you really want to exit, in case you{typed X by mistake.)  I'll remember exactly where we left off, so when you're{ready to learn again, you'll be able to go back there or to any other lesson.{Remember, just type X at any time to exit^ADA-TUTR`.{{%ADA-TUTR~works with monochrome as well as color computers.  Please adjust the{brightness and contrast of your screen now, so that the^highlighted~words are{noticeably brighter than the others, but all are easy to read.  You can set the{colors at any time by typing S, and I'll remember your color choices.{{Please send your comments and suggestions to Software Innovations Technology,{Attention: John J. Herro, 1083 Mandarin Drive NE, Palm Bay, FL 32905-4706.{}Please type a space to go on.  (You need not hit ENTER.)[ 121B104]@>PRINTED COURSE NOTES{{To get the most from^ADA-TUTR`, you should have a printed copy of the PRINT.ME{file.  If you haven't started printing the course notes yet, read this screen{and then type X to exit the program temporarily.  Remember, you can leave{%ADA-TUTR~at any time, and later pick up exactly where you left off.{{Then, when the system prompt (usually^C>`) appears, type:{{@@^PRINT PRINT.ME`{{You can then restart^ADA-TUTR~while your course notes are being printed.{Please read them through page 2 now.  If you got this far, you don't need page{6.  Please read page 43 if you want to install^ADA-TUTR~on a non-PC computer,{such as a workstation or a mainframe.{{In addition to the printed course notes, we recommend (but don't require) that{you have access to the Military Standard Ada Programming Language manual,{ANSI/MIL-STD-1815A, 1983.  This volume is often called the^Language Reference{Manual`, or^LRM`.  You'll probably find it in a public library, or perhaps in{your company library.  If you can borrow an LRM, it's legal to copy the entire{book.  You can also buy an LRM very inexpensively.{}Please type X to exit, a space to go on, or B to go back.[ 122B120]@5DO I NEED A TEXTBOOK FOR THIS COURSE?{{Although the LRM is a good reference, it's difficult reading and not a good{learning tool.  With^ADA-TUTR~you probably won't need a textbook, but we made a{special arrangement with John Wiley and Sons in case you would like to have a{textbook to go along with this course.  If you copy page 37 of PRINT.ME, or{print the file COUPON.TXT, you can purchase the excellent textbook RENDEZVOUS{WITH ADA by David Naiditch for a very good price.  Be sure to send your order{to the address on the coupon, not to us.{{If you're using a PC and you ever want to print the screen that's currently{being displayed, just hold a Shift key while pressing the^PrtSc~key.{{A few of you asked us for a way to print^all~the screens in this course, so we{added the program^BOOK~to^ADA-TUTR`.  While this is by no means required, or{even recommended, if you want a printout of all the screens, please see page 38{of your printed course notes for instructions on running^BOOK`.  Be prepared to{print about 500 pages!{}b[ 123B121]@3DO I NEED AN ADA COMPILER FOR THIS COURSE?{{An Ada compiler is helpful, but not required.  As we go along, there will be{six Outside Assignments; most of them ask you to write and compile a short Ada{program.  If you don't have access to an Ada compiler, just skip the Outside{Assignments.{{A brief list of Ada compilers available for the PC and compatibles is in your{printed course notes, on page 39.  We tried to include all the popular Ada{compilers, but we might have missed some.  If you know of an Ada compiler that{you think should be on that list, please contact us.{{A screen editor / word processor is very helpful, and we can send you a copy of{one free or nearly free.  Please see page 42 of your printed course notes for{details.{{That's enough discussion of what's recommended for^ADA-TUTR`.  Let's begin!{}b[ 124B122]@;^ADA-TUTR COURSE OUTLINE`{{{%>  INTRODUCTION~@<Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 125B123]@BWHAT IS ADA?{{Ada is a modern language designed for programming large scale and real time{systems.  Ada is also an excellent general purpose language.  It has many new{features which help prevent errors and detect errors earlier.{{However, Ada is much more than a new language.  It's also a new programming{%philosophy`.  Beware of learning just "Ada syntax"; you'll wind up writing{Basic-like (or Pascal-like, etc.) programs that happen to be coded in Ada.  If{you do that, you'll lose the many benefits of Ada.  Unfortunately, you won't{see why Ada is a new programming philosophy until later in this course.  (By{the time we get to packages and information hiding, you'll be an enthusiastic{convert.)  In the meantime, please take our word for it:  Ada is a whole new{programming philosophy, not just another language.{{Because of its many features, Ada is relatively complicated.  There's about{seven times as much to learn as Pascal.  However, the effort pays great{dividends.  Once you learn the language, Ada programs are easier to write,{easier to read, and much easier to modify a month or a year later.{}b[ 126B124]@:A VERY BRIEF HISTORY OF ADA{{Ada was named for Augusta Ada Byron, countess of Lovelace and daughter of the{poet Lord Byron.  She worked with Charles Babbage on his Analytical Engine, and{has been called the world's first programmer.  The Language Reference Manual{(LRM) was given the number ANSI/MIL-STD-1815A because Augusta Ada Byron was{born in 1815.{{Ada was invented because the U.S. Department of Defense (DoD) realized that{none of the existing languages was very suitable for real-time control of{large, embedded systems.  An embedded system is a computer system inside a{product other than a computer, such as an intelligent oven or a guided missile.{Programs for embedded systems are usually written with a^cross compiler`, a{compiler that runs on one machine and produces code for another.  Cross{compilers are often called compilers for short.{{In 1977 the DoD issued a Request for Proposal to develop a new language; the{leading four contenders were designated Blue, Red, Yellow, and Green.{Eventually Green was selected to be Ada; it was designed by the company{Honeywell Bull under the direction of Jean Ichbiah of France.{}b[ 127B125]In the author's opinion, which^one~of the following statements is true?{{{1.  Ada is simpler than Pascal.{{2.  Although Ada was designed for embedded systems, it makes a good general{@$purpose language.{{3.  Basic and Pascal programs can easily be translated into good Ada programs.{{4.  In languages that are simpler than Ada, errors are usually detected earlier{@$than in Ada.{}Please press 1, 2, 3, or 4, or B to go back.[2128112931304131B126]%You're right!~ Ada makes use of the latest advances in software engineering, so{it makes an excellent general purpose language.{}q[ 132B127Q127]No, Ada is more complicated than Pascal.  So far as the^philosophy~is{concerned, Ada is an extension (or "superset") of Pascal.  However, in^syntax`{Ada isn't a superset of Pascal; the Ada syntax is different.{{Although Ada is more complicated than Pascal (and many other languages), it has{many advantages.  These advantages pay dividends in reduced effort to develop{and maintain programs.{}q[ 132B127Q127]No, it might be easy to translate Basic and Pascal programs into Ada, but the{resulting programs wouldn't be very good, because they'd fail to take advantage{of the features of Ada.{}q[ 132B127Q127]No, Ada has a reputation for detecting errors earlier than the simpler{languages.  Ada detects errors at compile time that other languages detect only{at run time or not at all.  Examples are calling a subprogram with the wrong{number of parameters, and unintentionally mixing different types in an{expression.  We'll learn more about these things later.{}q[ 132B127Q127]@7WHAT'S A "VALIDATED" ADA COMPILER?{{Although the name "Ada" is no longer a trademark of the Department of Defense,{the Ada Joint Program Office (AJPO) still validates Ada compilers (and cross{compilers).  If a compiler conforms exactly to the standard, and isn't a subset{or superset of Ada, it can be validated after passing an extensive suite of{tests (called the Ada Compiler Validation Capability, or ACVC).{{The ACVC is updated periodically.  Only currently validated compilers may{display an emblem that says, "Validated Ada ... This product conforms to{ANSI/MIL-STD-1815A as determined by the AJPO under its current testing{procedures."{{An unnumbered page in the beginning of the LRM says that "Only compilers which{have been validated ... shall be used in DoD systems."  Also, a 1987 DoD{Directive (3405.2) says that only validated Ada compilers may be used on{mission critical systems.{{True or False?  Subsets and supersets of standard Ada may be called "Ada."{}Please press T for true or F for false, or B to go back.[T133F134B127]%You're right!~ Compilers not conforming exactly to the Ada standard may be{called "Ada."  This was true even when "Ada" was a DoD trademark.  A preface to{the LRM says that compilers not conforming to the standard may be called "Ada"{if there's a clear statement that they don't conform.{{Of course, only validated Ada compilers are to be used on DoD systems, and{validated compilers can't be subsets or supersets of standard Ada.{}q[ 135B132Q132]True.  It's a common misconception that subsets and supersets may not be called{"Ada."  However, this was allowed even when "Ada" was a DoD trademark.  A{preface to the LRM says that compilers not conforming to the standard may be{called "Ada" if there's a clear statement that they don't conform.{{It's true that only validated Ada compilers are to be used in DoD systems.{Validated compilers can't be subsets or supersets of standard Ada.{}q[ 135B132Q132]True or False?  The Validation tests are performed to provide reasonable{assurance that a compiler is bug-free.{}Please press T for true or F for false, or B to go back.[F136T137B132]%You're right!~ The Validation tests are performed to make sure that a compiler{conforms to the Ada standard, and isn't a subset or superset.  A compiler isn't{believed to be bug-free just because it earned a Validation Certificate.{}q[ 138B135Q135]False.  That's a common misconception, but validation only determines that a{compiler conforms exactly to the Ada standard, and isn't a subset or superset.{A compiler isn't believed to be bug-free just because it earned a Validation{Certificate.{}q[ 138B135Q135]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{%>  THE FORMAT OF AN ADA PROGRAM~@,Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 139B135]@=OUR FIRST ADA PROGRAM{{Now let's look at a simple Ada program.  This program merely displays "Hello!"{on the screen.{{@8^with TEXT_IO;`{@8^procedure HELLO is`{@8^begin`{@;^TEXT_IO.PUT_LINE("Hello!");`{@8^end HELLO;`{{TEXT_IO is a "package" that comes with the Ada language.  We'll learn more{about packages later.  TEXT_IO contains, among other things, a procedure{PUT_LINE that takes one parameter of type STRING and displays it.  In this{case, the STRING parameter is^"Hello!"`.  Ada doesn't have any special I/O{statements.  I/O is done by calling procedures that Ada provides for us.{{Even though the package TEXT_IO comes with Ada, our procedure HELLO can't "see"{it unless it says^with TEXT_IO;`.  With that statement, our procedure can call{any procedure or function inside TEXT_IO.  We call a procedure by giving the{package name (TEXT_IO), followed by a dot and the name of the procedure within{the package.  Like Pascal and unlike Fortran, the word CALL isn't used in Ada.{}b[ 140B138]@8^with TEXT_IO;`{@8^procedure HELLO is`{@8^begin`{@;^TEXT_IO.PUT_LINE("Hello!");`{@8^end HELLO;`{{The statement^with TEXT_IO;~is called a^context clause~because it specifies the{"context" in which procedure HELLO is compiled.{{In Ada a^procedure~may be called either from another procedure or as the main{program.  In this example, HELLO is the main program; it calls PUT_LINE.{{Every Ada statement, including the last, ends with a semicolon.  (Technically,{the lines above without semicolons aren't statements.)  In Pascal, semicolons{come^between~statements, but in Ada, a semicolon^ends~a statement.{{In Ada, the^end~statement may optionally give the name of the procedure or{function.  If a name is given, the compiler will check that it agrees with the{name at the beginning.  If it doesn't agree, the compiler will issue a message.{{The statements between^begin~and^end~(this program has only one) are called{executable statements; when they're obeyed they're said to be^executed`.{}b[ 141B139]@?LOCAL DECLARATIONS{{@9with TEXT_IO;{@9procedure HELLO is{@;^I@$: INTEGER;`{@;^X, Y : FLOAT;`{@9begin{@<TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{Local declarations may appear between^procedure ... is~and^begin`.  This simple{program doesn't need any, but we've added two declarative statements by way of{example.  Executable statements are said to be^executed~when they're obeyed,{but when a declarative statement is obeyed, it's said to be^elaborated`.{Declarative statements are elaborated at run time, not compile time.{{In this example, when the procedure is called (either from another procedure or{as the main program), the declarations are elaborated and variables I, X, and Y{are brought into existence.  Then the executable statement(s) are obeyed.  When{the^end~statement is reached and the procedure returns, I, X, and Y go out of{existence.  These three variables are local to procedure HELLO and can't be{referenced outside this procedure.{}b[ 142B140]@9with TEXT_IO;{@9procedure HELLO is{@;^I@$: INTEGER;`{@;^X, Y : FLOAT;`{@9begin{@<TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{If HELLO is called again, I, X, and Y will again be brought into existence, but{their previous values won't necessarily be remembered between calls.  (Of{course, in this simple example, I, X, and Y aren't assigned values anyway.){{Like Pascal and unlike Basic and Fortran, every Ada variable must be declared.{(The index of an Ada^for~loop declares itself, but we'll discuss that later.){Unlike Pascal, Ada programs don't need to say "var".  Ada knows that the{objects declared above are variables.  Constant declarations contain the{reserved word^constant~and may or may not specify a type, like this:{{@5^PI@%: constant := 3.141592654;`{@5^TWO_PI : constant FLOAT := 2.0 * PI;`{{Constant declarations that don't specify a type are called^named numbers`.{}b[ 143B141]@5^PI@%: constant := 3.141592654;`{@5^TWO_PI : constant FLOAT := 2.0 * PI;`{{Declarations are elaborated in order, top to bottom.  The two declarations{above must appear in the order shown, because the second refers to the first.{{The difference between a named number, like PI, and a constant declaration that{specifies a type, like TWO_PI, is subtle.  We'll explain the difference in the{Advanced Topics section under "Universal Types."  For now, it doesn't make any{difference whether or not a constant declaration specifies a type.  The{compiler can tell, from looking at the constant, whether the type is INTEGER or{FLOAT.{{Unlike Pascal, Ada allows constant declarations to be intermixed with variable{declarations, so long as no declaration refers to a declaration below it.{}b[ 144B142]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{OK, in the program above, where are the^executable statement(s)`?{}Please press 1, 2, or 3, or B to go back.[314511462147B143]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@.^3@,TEXT_IO.PUT_LINE("Hello!");`{@9end HELLO;{{%You're right!~ Executable statements are placed between^begin~and^end`.{}q[ 148B144Q144]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{No,^with TEXT_IO;~is a^context clause`.  Executable statements are placed{between^begin~and^end`.{}q[ 148B144Q144]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{No,^declarative~statements are placed between^procedure ... is~and^begin`.{%Executable~statements are placed between^begin~and^end`.{}q[ 148B144Q144]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{Now, where are the^local declaration(s)`?{}Please press 1, 2, or 3, or B to go back.[214911503151B144]@/1@)with TEXT_IO;{@9procedure HELLO is{@.^2@,I@$: INTEGER;`{@;^X, Y : FLOAT;`{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{%You're right!~ Local declarations are placed between^procedure ... is~and{%begin`.{}q[ 152B148Q148]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{No,^with TEXT_IO;~is a^context clause`.  Local declarations are placed between{%procedure ... is~and^begin`.{}q[ 152B148Q148]@/1@)with TEXT_IO;{@9procedure HELLO is{@/2@,I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@/3@,TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{No,^executable~statements are placed between^begin~and^end`. ^Local declarations`{are placed between^procedure ... is~and^begin`.{}q[ 152B148Q148]@;CAPITALIZATION AND SPACING{{@9with TEXT_IO;{@9procedure HELLO is{@<I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@<TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{Except in quoted STRINGs like "Hello!", capitalization isn't important in Ada.{The LRM shows all reserved words in lower case and all identifiers in upper{case, so that's the style we're using in our examples.{{In Ada, unlike Fortran, statements may begin anywhere on the line; columns{aren't significant.  Most people indent the local declarations and the{executable statements two or three spaces, as shown above.  Spaces and tabs may{not appear^within~reserved words and identifiers, but they may freely be used{%between~elements of the program.{}b[ 153B148]@9with TEXT_IO;{@9procedure HELLO is{@<I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@<TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{Since a semicolon marks the end of a statement, we can put several statements{on one line, like this:{{@:I : INTEGER;@#X, Y : FLOAT;{{We can also continue a statement over several lines, breaking anywhere a space{would be permitted, like this:{{@@TEXT_IO.{@EPUT_LINE({@E"Hello!");{{Many people follow the capitalization and spacing style of the LRM, so we'll do{that in this course.{}b[ 154B152]@DCOMMENTS{{@*with TEXT_IO;{@*procedure HELLO is{@,^-- This program displays "Hello!" on the screen.`{@-I@$: INTEGER;^-- These declarations aren't needed; they`{@-X, Y : FLOAT;  ^-- were added only to provide examples.`{@*begin{@-TEXT_IO.PUT_LINE("Hello!");{@*end HELLO;{{Comments in Ada begin with a double hyphen (double minus sign) and continue{through the end of the line.  No space is permitted inside the double hyphen.{As shown, a comment can be an entire line, or it can follow code on a line.{{Ada programs generally have less need for comments than programs written in{other languages.  The reason is that, as we'll see, the identifiers may be as{long as we like (up to the length of a line) and can have very meaningful{names.  Also, when we learn about named notation, we'll see that calls to{subprograms can be made much more readable in Ada than in other languages.{These features and others tend to make Ada programs self documenting.{}b[ 155B153]@BIDENTIFIERS{{@9with TEXT_IO;{@9procedure HELLO is{@<I@$: INTEGER;{@<X, Y : FLOAT;{@9begin{@<TEXT_IO.PUT_LINE("Hello!");{@9end HELLO;{{In this program,^reserved words~are in lower case, and all other^identifiers`{are in upper case.  (The 63 Ada reserved words, which may not be used to{identify anything in our programs, are listed on page 7 of your printed course{notes, and in section 2.9 of the LRM.)  Ada identifiers may contain letters,{digits, and underlines, but must start with a letter.  They may not contain{spaces or other characters.  Identifiers may be as long as you like, up to the{length of a line.  (The maximum line length depends on the particular implemen-{tation of Ada.)  All characters are significant, so THIS_IS_A_LONG_IDENTIFIER_1{and THIS_IS_A_LONG_IDENTIFIER_2 are distinct.  Since underlines are{significant, A_B is different from AB.  Every underline must be followed by a{letter or a digit.  Thus, you can't have two underlines together, and an{identifier can't end in an underline.{}b[ 156B154]@11.  1553B{{@12.  BEGIN{{@13.  This_Is_a_Very_Long_Name_for_an_Identifier{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{Only^one~of the above is a legal Ada identifier.  Which is it?{}Please press 1, 2, 3, 4, 5, or 6, or B to go back.[315711582159416051616162B155]@11.  1553B{{@12.  BEGIN{{@0^3.  This_Is_a_Very_Long_Name_for_an_Identifier`{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{%You're right!~ An Ada identifier may be as long as we like (up to the length of{a line), and upper/lower case isn't important in Ada.{{Number 1 begins with a digit, 2 is a reserved word, 4 has a dollar sign, 5 has{a trailing underline, and 6 has a space.{}q[ 163B156Q156]@11.  1553B{{@12.  BEGIN{{@13.  This_Is_a_Very_Long_Name_for_an_Identifier{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{No, number 1 is illegal because Ada identifiers must begin with a letter.{}q[ 163B156Q156]@11.  1553B{{@12.  BEGIN{{@13.  This_Is_a_Very_Long_Name_for_an_Identifier{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{No, number 2 is illegal because^begin~is a reserved word.{}q[ 163B156Q156]@11.  1553B{{@12.  BEGIN{{@13.  This_Is_a_Very_Long_Name_for_an_Identifier{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{No, number 4 is illegal because of the dollar sign.  Ada identifiers may{contain only letters, digits, and underlines.{}q[ 163B156Q156]@11.  1553B{{@12.  BEGIN{{@13.  This_Is_a_Very_Long_Name_for_an_Identifier{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{No, number 5 is illegal because of the trailing underline.  Every underline{must be followed by a letter or a digit.  You can't have a trailing underline,{and you can't have two underlines together.{}q[ 163B156Q156]@11.  1553B{{@12.  BEGIN{{@13.  This_Is_a_Very_Long_Name_for_an_Identifier{{@14.  SYS$QIO{{@15.  NUMBER_OF_TARGETS_{{@16.  MAX SPEED{{{No, number 6 is illegal because of the space.  Ada identifiers may contain only{letters, digits, and underlines.{}q[ 163B156Q156]@DNUMBERS{{In numbers, unlike identifiers, underlines are^not~significant.  Thus^12345~and{%12_345~are equivalent.  Spaces aren't permitted within numbers.  When an{underline appears in a number, it must be surrounded by digits.  Thus, all of{these are illegal:@%123_@%123_.0@%_123@%12__3{{Floating point numbers must have at least one digit before and one digit after{the decimal point.  Unlike Basic and Fortran, Ada forces us to write^1.0`{instead of^1.`, and^0.5~instead of^.5`.  Scientific notation may be used:^1.3E-3`{is the same as^0.0013`.  Non-negative exponents may be used even in integers:{%12E3~means^12_000`.{{Numbers may be specified in any base from 2 to 16, as shown below.  These three{numbers are all equal:{{@*^16#7C03#@)2#0111_1100_0000_0011#@)8#076003#`{{A number with a base may have an exponent.  The number after the^E~is still{written in decimal, and gives the power by which the base is raised.  Thus{%2#110#E5~is 6 times 2**5, or 192.{}b[ 164B156]@7MAKING THE DOT NOTATION AUTOMATIC{{These two programs are equivalent:{{@&with TEXT_IO;@;with TEXT_IO;^use TEXT_IO;`{@&procedure HELLO is@6procedure HELLO is{@&begin@Cbegin{@(^TEXT_IO.`PUT_LINE("Hello!");@-PUT_LINE("Hello!");{@&end HELLO;@>end HELLO;{{We've said that the statement^with TEXT_IO;~makes the package^visible`, so that{our program can call the procedures and functions in it.  To call a procedure,{we write the name of the package, a dot, and the name of the procedure.{{The statement^use TEXT_IO;~tells the compiler to supply the name of the package{and the dot for us.  That's why the two programs above are equivalent.{{Remember, in Ada^with~provides visibility;^use~asks the compiler to supply the{package name and the dot.{{The Ada meanings of the words^with~and^use~are more or less reversed from their{meanings in Pascal.  Also, in Ada one can't^use~records, only packages.{}b[ 165B163]@&with TEXT_IO;@;with TEXT_IO;^use TEXT_IO;`{@&procedure HELLO is@6procedure HELLO is{@&begin@Cbegin{@(^TEXT_IO.`PUT_LINE("Hello!");@-PUT_LINE("Hello!");{@&end HELLO;@>end HELLO;{{A program can^with~and^use~several packages.  For example, there's a package{that comes with Ada called CALENDAR.  Suppose we've also compiled two packages{of our own, called MY_PKG_1 and MY_PKG_2.  Then our program might say{{@1^with TEXT_IO, CALENDAR, MY_PKG_1, MY_PKG_2;`{@1^use  TEXT_IO, CALENDAR, MY_PKG_1, MY_PKG_2;`{{In this case, when the compiler sees the call to PUT_LINE, it will search all{four packages that we've^use`d for a procedure PUT_LINE that takes one STRING{parameter (or "argument").  If it finds no procedure PUT_LINE, the compiler{will display an error message, like "PUT_LINE is not declared" or "Undeclared{identifier PUT_LINE."{{You may ask, what if there are several procedures PUT_LINE among the four{packages?  Will the compiler stop searching when it finds the first PUT_LINE?{No.{}b[ 166B164]@1^with TEXT_IO, CALENDAR, MY_PKG_1, MY_PKG_2;`{@1^use  TEXT_IO, CALENDAR, MY_PKG_1, MY_PKG_2;`{{If the compiler finds several PUT_LINEs, the name PUT_LINE is said to be{%overloaded`.  In that case the compiler will use the^number~and^types~of{parameters (arguments) to try to select the right PUT_LINE.  For example, if{TEXT_IO contains a PUT_LINE that takes one STRING parameter, and MY_PKG_1{contains a PUT_LINE that takes one INTEGER parameter, the compiler will write a{call to TEXT_IO.PUT_LINE and not MY_PKG_1.PUT_LINE, because the calling{statement supplies one STRING parameter.{{If there's more than one PUT_LINE that takes exactly one STRING parameter, then{the call is ambiguous and the compiler can't resolve the overloading.  The{error message will be something like "Ambiguity detected during overload{resolution" or "Ambiguous expression."  In that case, we'd have to specify{%TEXT_IO.`PUT_LINE even though we said^use TEXT_IO;`.{{Finally, if there are procedures PUT_LINE, but none of them has the right{number and types of parameters, the error message will be something like{"Inconsistency detected during overloading resolution" or "Unresolvable{expression."{}b[ 167B165]In summary, the compiler will search all the packages that we've^use`d for a{procedure with the correct number and types of parameters.  If it finds exactly{one, everything's fine.  If it finds no procedure with the correct name, the{error message will be something like "Undeclared identifier."  If it finds more{than one procedure with the correct number and types of parameters, the message{is "Ambiguity detected during overload resolution" or "Ambiguous expression."{Finally, if it finds one or more procedures with the correct name, but none of{them has the right number and types of parameters, the message will be{something like "Inconsistency detected during overload resolution" or{"Unresolvable expression."{{Overloading may seem like an unnecessary complication at this point, but you'll{see later how very useful it can be.  Overloading is especially useful with{the infix operators when we create our own types.  All of this will be covered{later.{}b[ 168B166]Which^one~of the following would most likely be the cause of the message{"Inconsistency detected during overload resolution"?{{{@$1.  You tried to^use~a package that you didn't^with`.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@$4.  You called a procedure or function with the wrong number or types of{@(parameters.{}Please press 1, 2, 3, or 4, or B to go back.[4169117021713171B167]@$1.  You tried to use a package that you didn't with.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@#^4.  You called a procedure or function with the wrong number or types of`{@'^parameters.`{{{%You're right!~ The message "Inconsistency detected during overload resolution"{usually means that you called a procedure or a function with the wrong number{or types of parameters.{}q[ 172B168Q168]@$1.  You tried to^use~a package that you didn't^with`.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@$4.  You called a procedure or function with the wrong number or types of{@(parameters.{{{No, for number 1 the message would be something like "This package is not named{in a prior^with~clause," or "%use~clause was not expected here."{}q[ 172B168Q168]@$1.  You tried to^use~a package that you didn't^with`.{{@$2.  You misspelled the name of a package in a call using dot notation.{{@$3.  You misspelled the name of a procedure or function in a call.{{@$4.  You called a procedure or function with the wrong number or types of{@(parameters.{{{No, if you misspell the name of a package, procedure, or function, the most{probable error message would be "Undeclared identifier."{}q[ 172B168Q168]TEXT_IO contains both a procedure^PUT~and a procedure^PUT_LINE~(among other{things). ^PUT_LINE~displays its STRING parameter followed by a Carriage Return{and a Line Feed, while^PUT~displays its STRING parameter without the CR-LF.{TEXT_IO also contains a procedure^NEW_LINE~which produces only CR-LF.  For{example, the following program will display^Hi there,~leave a blank line, and{display^everybody!`:{{@:with TEXT_IO; use TEXt_IO;{@:procedure HI_THERE is{@:begin{@<^PUT`("Hi");{@<^PUT_LINE`(" there,");{@<^NEW_LINE;`{@<^PUT_LINE`("everybody!");{@:end HI_THERE;{}b[ 173B168]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{%>  GENERIC INSTANTIATION AND~@/Subprograms and Packages{@%^ASSIGNMENT 1`{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 174B172]@>DISPLAYING INTEGERS{{with TEXT_IO; use TEXT_IO;@;with TEXT_IO; use TEXT_IO;{procedure HELLO is@,^THIS~@'^THIS~@$procedure ADD is{begin@6^<= IS~@+^IS =>~ begin{@#PUT_LINE(%"Hello!"`);@(^RIGHT~@%^WRONG~@'PUT_LINE(%2 + 2`);{end HELLO;@Kend ADD;{{Now let's write a program called ADD that computes 2 + 2 and displays the{result.  You may think that we could take the HELLO program and substitute{%2 + 2~for^"Hello!"`, but that won't work.  (We never said Ada is easy!)  Why{won't it work?  Because TEXT_IO doesn't have a procedure PUT_LINE that takes an{INTEGER parameter.  One correct program is this:{{@(with TEXT_IO; use TEXT_IO;{@(procedure ADD is{@*^package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;`{@(begin{@*^PUT(2 + 2);`{@*^NEW_LINE;`{@(end ADD;{}b[ 175B173]@(with TEXT_IO; use TEXT_IO;{@(procedure ADD is{@*^package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;`{@(begin{@+PUT(2 + 2);{@+NEW_LINE;{@(end ADD;{{__________ TEXT_IO __________  The package TEXT_IO contains procedures for type{| PUT_LINE for type STRING  |  STRING.  This package is ready-to-use.  However,{| PUT@&for type STRING  |  inside TEXT_IO is another package, INTEGER_IO,{| GET_LINE for type STRING  |  that's^not~ready-to-use.  It's called a^generic`{| GET@&for type STRING  |  package because it has an empty^box~(%<>`) in{| NEW_LINE@2|  place of the type.  We can make a new, ready-to-{| ...@7|  -use package from INTEGER_IO by giving the type:{|@;|  package MY_INT_IO is new INTEGER_IO(%INTEGER`); we{|  ______ INTEGER_IO ______ |  could have used any name in place of MY_INT_IO.{|  | PUT for type <>@&| |  Note that we've declared our new package locally{|  | GET for type <>@&| |  inside the procedure ADD.  MY_INT_IO now has the{|  | ...@2| |  same procedures and functions as INTEGER_IO, but{|  |______________________| |  with the empty box filled in with the type{|___________________________|  INTEGER, like this:{}b[ 176B174]@@with TEXT_IO; use TEXT_IO;{__________ TEXT_IO __________@#procedure ADD is{| PUT_LINE for type STRING  |@%^package MY_INT_IO is new INTEGER_IO(`{| PUT@&for type STRING  |@*^INTEGER); use MY_INT_IO;`{| GET_LINE for type STRING  |@#begin{| GET@&for type STRING  |@%^PUT(2 + 2);`{| NEW_LINE@2|@%^NEW_LINE;`{| ...@7|@#end ADD;{|@;|{|  ______ INTEGER_IO ______ |@#^______ MY_INT_IO _______`{|  | PUT for type <>@&| |@#^| PUT for type INTEGER |`{|  | GET for type <>@&| |@#^| GET for type INTEGER |`{|  | ...@2| |@#^| ...@2|`{|  |______________________| |@#^|______________________|`{|___________________________|{{Since INTEGER_IO (and therefore MY_INT_IO) doesn't have a PUT_LINE, we call{MY_INT_IO.PUT and then TEXT_IO.NEW_LINE.  Note that our program says{%use MY_INT_IO;~after declaring MY_INT_IO.  When the compiler sees the call{%PUT(2 + 2);~it writes code to call MY_INT_IO.PUT rather than TEXT_IO.PUT,{because MY_INT_IO.PUT takes a parameter of type INTEGER.  The compiler then{finds NEW_LINE in TEXT_IO and writes a call to TEXT_IO.NEW_LINE.{}b[ 177B175]True or False?  In our example, a program could call^INTEGER_IO.PUT`.{}Please press T for true or F for false, or B to go back.[F178T179B176]%You're right!~ Since INTEGER_IO is generic, a program can't call its procedures{and functions.  The program must specify the type and create an^instance~of{INTEGER_IO, such as MY_INT_IO.  It can then call PUT in MY_INT_IO.  Note also{that we can't^use~a generic package like INTEGER_IO, but only an instance of it{like MY_INT_IO.{}q[ 180B177Q177]False.  Since INTEGER_IO is generic, a program can't call its procedures and{functions.  The program must specify the type and create an^instance~of{INTEGER_IO, such as MY_INT_IO.  It can then call PUT in MY_INT_IO.  Note also{that we can't^use~a generic package like INTEGER_IO, but only an instance of it{like MY_INT_IO.{}q[ 180B177Q177]@=GENERIC INSTANTIATION{{@0^package MY_INT_IO is new INTEGER_IO(INTEGER);`{{@.______ INTEGER_IO ______@#^______ MY_INT_IO _______`{@.| PUT for type <>@&|@#^| PUT for type INTEGER |`{@.| GET for type <>@&|@#^| GET for type INTEGER |`{@.| ...@2|@#^| ...@2|`{@.|______________________|@#^|______________________|`{{This process of creating an^instance~of the generic package INTEGER_IO for the{type INTEGER is called^generic instantiation`.  Later in this course we'll{learn to write our own generic packages, procedures, and functions.  However,{we wanted to learn, early in the course, how to instantiate an already written{generic package in order to display integers.{{But why does Ada make TEXT_IO ready-to-use for STRINGs, while INTEGER_IO is{generic, and has to be instantiated for INTEGERs?  Because programs normally{use only one type STRING, but can have several integer types.  Right now, we{know of only one integer type, the standard INTEGER.  Later we'll learn about{user-defined types and derived types, and we'll see how there can be many{integer types.  INTEGER_IO can be instantiated for each of these types.{}b[ 181B177]Since INTEGER_IO is often instantiated for the standard INTEGER type, some{implementations of Ada provide an already-instantiated package for the type{INTEGER, equivalent to our package MY_INT_IO.  However, an implementation of{Ada need not supply such a package to meet the Ada standard.  Our program did{its own instantiation of INTEGER_IO so that it would run on any Ada that meets{the standard.{{There's another generic package within TEXT_IO called FLOAT_IO.  Input and{output of floating point numbers is done by instantiating FLOAT_IO for the type{FLOAT.  As with integers, we'll later learn how there can be several floating{point types besides the standard FLOAT.{{Later in this course, when we cover attributes, we'll learn another way to{display INTEGERs.  However, that other method won't work for FLOATs.  The way{we just learned, instantiating a generic package, works for FLOATs as well as{INTEGERs.{{We're now ready for our first Outside Assignment!  Let's compile and run our{two sample programs, HELLO and ADD.{}b[ 182B180]@*OUTSIDE ASSIGNMENT 1 - PREPARING TO RUN ADA ON YOUR COMPUTER{{Since these screens disappear, you'll probably want to refer to your printed{course notes when doing the Outside Assignments.  The first assignment appears{on page 8.  In this assignment, we'll compile, link, and run our first two{programs, HELLO and ADD.{{First compile HELLO.ADA, then link, and then execute the program.  The exact{steps will depend on the Ada compiler you're using.  You'll probably have to{refer to the documentation that came with your compiler.  Note that some{implementations of Ada use the term "binding" instead of "linking."  When you{run the program, it should display^Hello!~on your screen.{{Then compile ADD.ADA, link, and run the program.{{When we compile, we specify the name of the source file being compiled.  Many,{but not all, implementations of Ada assume the extension to be .ADA if it's not{specified.  When we link, we specify the name of the main program, which in our{examples agrees with the name of the source file.  The linking step produces a{file which we can execute.{}b[ 183B181]Before we can compile an Ada program, we must create our own Ada library.  Some{implementations of Ada come with a library already created for us; others{require us to type a command to create a library.  When we compile HELLO.ADA{and ADD.ADA, the procedures HELLO and ADD are added to our library.  We'll{discuss the Ada library in more detail later.{{If you haven't done so already, please type X to exit^ADA-TUTR~temporarily,{read page 8 of your printed course notes, and try the first Outside Assignment.{{When you finish Outside Assignment 1, we'll go on to discuss the Ada library{and separate compilation of program units.{}Please type X to exit, a space to go on, or B to go back.[ 184B182]@-^Congratulations on Completing Outside Assignment 1!`{{We know this first assignment wasn't very interesting, because the programs{HELLO.ADA and ADD.ADA were supplied for you.  But we had to be sure we can{compile, link, and execute Ada programs, so we can do the remaining{assignments.{{The rest of the Outside Assignments should be more challenging!{{Let's go on to discuss the Ada library and separate compilation of program{units.{}b[ 185B183]@@THE ADA LIBRARY{{What's the difference between an Ada library, and, say, a Fortran library?{Compilers for languages other than Ada simply take source code and produce{object code.  Compiling a Fortran program doesn't change the Fortran library.{Ada compilers, however, take source code and a library and produce object code{and an updated library. ^The Ada library remembers what we've compiled.~ Other{languages have libraries of functions, etc., but they're fixed and don't{remember what we've compiled.{@@________________{@?|@0|{@-Source Code@'|  Fortran,@&|@&Object Code{@'----------------------->|  Pascal, etc.  |----------------------->{@?|  Compiler@&|{@?|________________|{{@@________________{@-Source Code@'|@0|@&Object Code{@'----------------------->|  Ada@+|----------------------->{@-Ada Library@'|  Compiler@&|  Updated Ada Library{@'----------------------->|@0|----------------------->{@?|________________|{}b[ 186B184]Ada gives us the advantage that compilation is^separate but dependent`.  Some{languages, such as Fortran, offer^separate and independent~compilation.  A{Fortran main program and a subroutine can be compiled independently, perhaps a{month apart.  When the subroutine is compiled, Fortran knows nothing about the{main program, and vice versa.  An advantage of^separate~compilation is that we{can develop our program one piece at a time and compile each piece as it's{developed.  However, the^independent~compilation is a disadvantage.  The{compiler can't check that the number and types of parameters in the call agree{with the number and types of parameters in the subroutine.  A Fortran main{program might say^CALL SUB(I, J, K)`, while the subroutine might say{%SUBROUTINE SUB(I, J)`.  Both of these will compile correctly.  When the program{is run, however, the results are unpredictable.  The program might simply give{wrong answers with no warning.{{Other languages, such as early Pascal and many versions of Basic, don't have{separate compilation at all.  The compiler could check the number and types of{parameters in a call, because the entire program must be compiled at one time.{But the advantages of separate compilation are lost.  We can't develop the{program one piece at a time, compiling each piece as it's developed.  And if we{make the slightest change in one part of the program, the whole program has to{be recompiled.{}b[ 187B185]Ada gives us the advantages of both systems, because compilation is^separate{but dependent`.  We can compile a subprogram today and the calling program next{month.  (We could also put both into one file and compile them together.)  Each{compilation unit updates the library when it's successfully compiled.  Thus,{when a call to a subprogram is encountered, the compiler will check the number{and types of parameters against the subprogram already in the library.{{We could also write the calling program^before~the subprogram, because Ada lets{us compile the subprogram^specification~separately from its^body`.  (We'll learn{more about that later.)  The specification contains the name of the subprogram,{and the names, number, and types of any parameters.  The specification also{tells which parameters are inputs, which are outputs, and which are both inputs{and outputs.  That's all the information the compiler needs to compile calls to{the subprogram; the body can be supplied later.  When the subprogram body is{compiled, the compiler will make sure it's consistent with the specification.{{Ada comes with several packages, such as TEXT_IO.  These are already compiled{and placed into the library.  That's why our programs can say^with TEXT_IO;~and{call its procedures and functions.{{Ada libraries are a complication compared to other languages, but they offer{great advantages in program development.{}b[ 188B186]True or False?  A procedure specification must be compiled before calls to the{procedure can be compiled.{}Please press T for true or F for false, or B to go back.[T189F190B187]%You're right!~ The specification contains all the information the compiler{needs to compile calls to the procedure.{}q[ 191B188Q188]True.  The compiler needs the information in the specification to compile calls{to the procedure.  However, the procedure^body~can be compiled later.{}q[ 191B188Q188]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{%>  SIMPLE DECLARATIONS AND SIMPLE~@-TEXT_IO, and Assignment 5{@%^ATTRIBUTES`{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 192B188]@=VARIABLES AND CONSTANTS{{@&procedure DECLARATIONS_DEMO is{@(^I, J, K : INTEGER;`{@(^L, M@$: INTEGER := 30;`{@)F, G@$: FLOAT;{@)FACTOR  : constant := 1000;{@&begin{@)J := L + 10;@*-- Simple assignment statements.{@)F := 0.0;{@)G := F + L;@+-- ILLEGAL.  Can't accidentally mix types.{@)G := F + FLOAT(L);@$-- Legal.  May deliberately convert types.{@)K := INTEGER(F) + L;  -- Legal.{@)FACTOR := 1000;@'-- ILLEGAL.  FACTOR is a constant.{@&end DECLARATIONS_DEMO;{{This program doesn't do anything except demonstrate Ada declarations.  The{statement^I, J, K : INTEGER;~brings three integer variables into existence.{The next statement creates two more integer variables and initializes both of{them to 30.  Every time this procedure is called, L and M are brought into{existence and initialized to 30.  This is different from a Fortran DATA{statement, which initializes only once at compile time.{}b[ 193B191]@&procedure DECLARATIONS_DEMO is{@)I, J, K : INTEGER;{@)L, M@$: INTEGER := 30;{@(^F, G@$: FLOAT;`{@(^FACTOR  : constant := 1000;`{@&begin{@(^J := L + 10;@*-- Simple assignment statements.`{@(^F := 0.0;`{@(^G := F + L;@+-- ILLEGAL.  Can't accidentally mix types.`{@)G := F + FLOAT(L);@$-- Legal.  May deliberately convert types.{@)K := INTEGER(F) + L;  -- Legal.{@)FACTOR := 1000;@'-- ILLEGAL.  FACTOR is a constant.{@&end DECLARATIONS_DEMO;{{The statement^F, G@$: FLOAT;~creates two variables of type FLOAT.  The next{statement names a constant.  Writing^FACTOR~is thereafter equivalent to writing{%1000`.  Unlike variables, constants^must~be initialized.{{The first two executable statements are simple assignment statements.  The{symbol^:=~is read "becomes" or "gets."  It may not contain a space.  In the{third executable statement, the compiler will reject the expression^F + L`{because Ada doesn't let us accidentally mix a FLOAT with an INTEGER.{}b[ 194B192]@&procedure DECLARATIONS_DEMO is{@)I, J, K : INTEGER;{@)L, M@$: INTEGER := 30;{@)F, G@$: FLOAT;{@)FACTOR  : constant := 1000;{@&begin{@)J := L + 10;@*-- Simple assignment statements.{@)F := 0.0;{@)G := F + L;@+-- ILLEGAL.  Can't accidentally mix types.{@(^G := F + FLOAT(L);@$-- Legal.  May deliberately convert types.`{@(^K := INTEGER(F) + L;  -- Legal.`{@(^FACTOR := 1000;@'-- ILLEGAL.  FACTOR is a constant.`{@&end DECLARATIONS_DEMO;{{However, Ada lets us^deliberately~mix types.  The statement^G := F + FLOAT(L);`{is legal because it converts L from INTEGER to FLOAT, adds it to F which is of{type FLOAT, and stores the result in G, also of type FLOAT.  Likewise, the next{statement is legal because it converts F to INTEGER, adds the integer L, and{stores the result in the integer K.  But note that when a FLOAT is converted to{INTEGER, it's rounded, not truncated.  (Later we'll present two functions that{truncate integers.)  The last executable statement is illegal because a{constant can't appear on the left side of an assignment statement.{}b[ 195B193]@'^with TEXT_IO; use TEXT_IO;`{@'^procedure TRY_ME is`{@*^package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;`{@*^N : INTEGER := 1;`{@'^begin`{@*^PUT(N);`{@*^NEW_LINE;`{@*^N := 2;`{@'^end TRY_ME;`{{What number will be displayed the^second~time procedure TRY_ME is called?{{@81.  The program will display 1.{{@82.  The program will display 2.{}Please press 1 or 2, or B to go back.[11962197B194]@'^with TEXT_IO; use TEXT_IO;`{@'^procedure TRY_ME is`{@*^package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;`{@*^N : INTEGER := 1;`{@'^begin`{@*^PUT(N);`{@*^NEW_LINE;`{@*^N := 2;`{@'^end TRY_ME;`{{%You're right!~ N is brought into existence and initialized to 1 each time the{procedure is called, so 1 will be displayed.{}q[ 198B195Q195]@(with TEXT_IO; use TEXT_IO;{@(procedure TRY_ME is{@+package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@+N : INTEGER := 1;{@(begin{@+PUT(N);{@+NEW_LINE;{@+N := 2;{@(end TRY_ME;{{No, N is declared locally within TRY_ME.  So N is brought into existence and{initialized to 1^each~time the procedure is called, and the procedure will{display 1 each time.  Also remember that N goes out of existence when TRY_ME{returns, so the statement N := 2; has no effect.{}q[ 198B195Q195]@?ENUMERATION TYPES{{In Ada we can declare^enumeration types`, where we enumerate every possible{value for a type.  For example, if we declare{{  ^type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);`{  ^RC : RAINBOW_COLOR;`{{then RC can have any of 7 values.  In the executable region we might write{%RC := RED;~and we could also test:^if RC = RED then~...^end if;`.  The{enumerated values, enclosed in parentheses, must follow the rules for Ada{identifiers, or they can be single^characters~enclosed in^'~marks (called "tic"{marks), thus:{{@1^type EVEN_DIGIT is ('0', '2', '4', '6', '8');`{{It's illegal to write^type PROCESSOR is (80386, Z80, 1750A);~because two of the{values aren't legal Ada identifiers.  However, it's OK to mix characters and{identifiers in the same declaration, thus:{{@4^type MIXED is (BIG, SMALL, 'X', '9');`{}b[ 199B195]  ^type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);`{  ^type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);`{  ^RC : RAINBOW_COLOR;`{  ^TC : TRAFFIC_LIGHT_COLOR;`{{With the above declarations, RC could have any of 7 values, and TC could have{any of 3 values.  The compiler will have no trouble compiling{{@B^RC := RED;`{@B^TC := RED;`{{because it knows that in^RC := RED;~RED must be the RAINBOW_COLOR if it's{stored into RC, and in^TC := RED;~RED must be the TRAFFIC_LIGHT_COLOR if it's{stored into TC.  The compiler knows that the types across^:=~must always match.{Naturally, it's illegal to write^RC := 2;~because of the mixed types.{{Also, if we have a procedure DISPLAY that takes one parameter of type{RAINBOW_COLOR, the compiler could handle^DISPLAY(RED);~because it knows that{RED must be the RAINBOW_COLOR to fit the procedure.{}b[ 200B198]  ^type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);`{  ^type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);`{{However, if we had a procedure DISPLAY that takes one RAINBOW_COLOR and another{procedure DISPLAY that takes one TRAFFIC_LIGHT_COLOR, then the statement{%DISPLAY(RED);~would be ambiguous; the compiler couldn't possibly know which{DISPLAY to call.  In that case, we could specify the type by writing{%RAINBOW_COLOR'(RED)`.  This is called^qualifying~the name RED; note the^'~with{the parentheses.  The call would be written^DISPLAY(RAINBOW_COLOR'(RED));`.  The{statements^DISPLAY(VIOLET);~and^DISPLAY(AMBER);~aren't ambiguous; the compiler{will figure out which DISPLAY to call in these cases.{{Declaring an enumeration type not only defines equality for objects of that{type, but also an order for the values.  Thus we can check for <, >, <=, etc.{For example, if we declare^A, B: RAINBOW_COLOR;~and later write, in the{executable region,^A := YELLOW;~and^B := BLUE;~then the test^if A < B then~...{%end if;~will turn out to be TRUE. ^YELLOW~is considered less than^BLUE`.{{Input and output of enumeration types can be done by instantiating the generic{package TEXT_IO.ENUMERATION_IO.  For example:{%with TEXT_IO; use TEXT_IO;~...{%package MY_RAINBOW_IO is new ENUMERATION_IO(RAINBOW_COLOR); use MY_RAINBOW_IO;`{}b[ 201B199]Here are two enumeration types built into the Ada language:{{@%^type BOOLEAN is (FALSE, TRUE);`{{@%^type CHARACTER is (~(nul)%,~(soh)%,~(stx)%,~...^, ' ', '!', '"',~...^,`{@9^'0', '1', '2',~...^, 'A', 'B', 'C',~...^,`{@9^'a', 'b', 'c',~...^,~(del)^);`{{Since the above two declarations are built into the Ada language, they{shouldn't be repeated in your programs.  Note that type BOOLEAN is just an{enumeration type.  The relational operators (^=`,^>`,^<=`, etc. ) all return{results of type BOOLEAN.{{The definition of type CHARACTER can't be completely written out, because there{are 33 unprintable ASCII characters.  However, the enumeration type CHARACTER{contains all 128 values, in ASCII character order.  On this screen, we've{denoted the unprintable characters with names in parentheses, and we've also{used "..." for brevity.  Even if Ada is run on an EBCDIC machine, it's{guaranteed that type CHARACTER contains the 128 ASCII characters in ASCII{character order.{}b[ 202B200]@.1.  type COUNT is ("1", "2", "3", "AB", "CD", "EF");{{@.2.  type COUNT is ('1', '2', '3', 'AB', 'CD', 'EF');{{@.3.  type COUNT is (1, 2, 3, AB, CD, EF);{{@.4.  type COUNT is ('1', '2', '3', AB, CD, EF);{{{Which^one~of the above type declarations is legal?{}Please press 1, 2, 3, or 4, or B to go back.[4203120422053206B201]@.1.  type COUNT is ("1", "2", "3", "AB", "CD", "EF");{{@.2.  type COUNT is ('1', '2', '3', 'AB', 'CD', 'EF');{{@.3.  type COUNT is (1, 2, 3, AB, CD, EF);{{@-^4.  type COUNT is ('1', '2', '3', AB, CD, EF);`{{{%You're right!~ Enumeration types can contain single characters between^'~marks,{and Ada identifiers.  Number 1 is illegal because it contains STRINGs, number 2{is illegal because^'~marks may enclose only single characters, and number 3 is{illegal because an Ada identifier can't begin with a digit.{}q[ 207B202Q202]@.1.  type COUNT is ("1", "2", "3", "AB", "CD", "EF");{{@.2.  type COUNT is ('1', '2', '3', 'AB', 'CD', 'EF');{{@.3.  type COUNT is (1, 2, 3, AB, CD, EF);{{@.4.  type COUNT is ('1', '2', '3', AB, CD, EF);{{{No, number 1 is illegal because an enumeration type can't contain STRINGs, only{single characters between^'~marks, and Ada identifiers.{}q[ 207B202Q202]@.1.  type COUNT is ("1", "2", "3", "AB", "CD", "EF");{{@.2.  type COUNT is ('1', '2', '3', 'AB', 'CD', 'EF');{{@.3.  type COUNT is (1, 2, 3, AB, CD, EF);{{@.4.  type COUNT is ('1', '2', '3', AB, CD, EF);{{{No, number 2 is illegal because only single characters may appear between^'`{marks.  Enumeration types contain single characters between^'~marks, and Ada{identifiers.{}q[ 207B202Q202]@.1.  type COUNT is ("1", "2", "3", "AB", "CD", "EF");{{@.2.  type COUNT is ('1', '2', '3', 'AB', 'CD', 'EF');{{@.3.  type COUNT is (1, 2, 3, AB, CD, EF);{{@.4.  type COUNT is ('1', '2', '3', AB, CD, EF);{{{No, number 3 is illegal because an Ada identifier can't begin with a digit.{Enumeration types can contain only single characters between^'~marks, and Ada{identifiers.{}q[ 207B202Q202]@DSUBTYPES{{A subtype does^not~define a new type, but it imposes a range constraint on{objects of that subtype.  For example,{{%subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{D : DAY_SUBTYPE; -- D can have only INTEGER values from 1 to 31.`{{type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{%subtype BRIGHT_COLOR is RAINBOW_COLOR range ORANGE .. GREEN;{B : BRIGHT_COLOR; -- B can have only RAINBOW_COLOR values from ORANGE to GREEN.`{{%subtype PROBABILITY is FLOAT range 0.0 .. 1.0;{P : PROBABILITY; -- P can have only FLOAT values from 0.0 to 1.0.`{{Every time the program stores a value into D, B, or P, a check is made to see{if the value is in range.  If it isn't, the message CONSTRAINT_ERROR is{displayed.  Constraint Errors are usually detected at run time.{{Since subtypes don't define new types, the^type~of D is INTEGER, the type of B{is RAINBOW_COLOR, and that of P is FLOAT.  Thus, if we write^I : INTEGER;~we{may write^D := D + I;~etc., because D and I have the same type.{}b[ 208B202]We don't have to supply a name for the subtype explicitly.  If we declare{{@:^D : INTEGER range 1 .. 31;`{{the compiler creates its own name for the subtype internally; we never see it.{This is called an^anonymous~subtype.  The name the compiler creates will be one{that we can't accidentally create ourselves.  Perhaps it will contain a control{character or punctuation mark that Ada doesn't allow us to put into an{identifier.  The above declaration is equivalent to{{@0^subtype~(something)^is INTEGER range 1 .. 31;`{@0^D :~(something)%;`{{where (something) represents the anonymous subtype that we can't see or write.{}b[ 209B207]@?SIMPLE ATTRIBUTES{{An^attribute~consists of an apostrophe (called a "tic" mark for short), and the{name of the attribute.  Attributes often follow type names.  They're something{like functions, except that they usually involve a type.  For example:{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{  ^RAINBOW_COLOR'SUCC(GREEN)~@&is^BLUE`{  ^TRAFFIC_LIGHT_COLOR'PRED(GREEN)~is^AMBER`{{The attributes^SUCC~and^PRED~stand for successor and predecessor, respectively.{In RAINBOW_COLORs, the successor of^GREEN~is^BLUE`, and in TRAFFIC_LIGHT_COLORs,{the predecessor of^GREEN~is^AMBER`.  Thus we could write^R : RAINBOW_COLOR;~and{then^R := RAINBOW_COLOR'SUCC(GREEN);`.  You'll get a CONSTRAINT_ERROR if you{try to take the successor of the last value or the predecessor of the first;{for example, taking RAINBOW_COLOR'PRED(RED) will cause an error.{{SUCC and PRED work with any^discrete type`.  That means any integer type or{enumeration type.  These two attributes aren't particularly useful with integer{types, because we can simply add or subtract 1 instead.  So they're usually{used with enumeration types.{}b[ 210B208]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{{The attribute^POS~converts from a discrete type to an integer, and^VAL~converts{from an integer to a discrete type.  Again, the type is usually an enumeration{type, because there's little point converting from integer to integer.{{For example,^RAINBOW_COLOR'POS(ORANGE)~is^1`.  (The positions are numbered from{zero.) ^RAINBOW_COLOR'POS(RED)~is^0~and^RAINBOW_COLOR'POS(VIOLET)~is^6`.{%TRAFFIC_LIGHT_COLOR'POS(GREEN)~is^2`, but^RAINBOW_COLOR'POS(GREEN)~is^3`.{%CHARACTER'POS('A')~is^65`, because the ASCII value of 'A' is 65, and the type{CHARACTER contains all 128 characters in ASCII order. ^CHARACTER'POS('0')~is{%48`, because the ASCII value of the character '0' is 48.{{%VAL~converts the other way, so^RAINBOW_COLOR'VAL(0)~is^RED`, and{%RAINBOW_COLOR'VAL(6)~is^VIOLET`.  Taking the RAINBOW_COLOR'VAL of a parameter{outside the range 0 .. 6 will raise a CONSTRAINT_ERROR. ^CHARACTER'VAL(65)~is{%'A'`, and^CHARACTER'VAL(7)~is the "bell" character (control-G).  Since BOOLEAN{is an enumeration type,^BOOLEAN'VAL(0)~is^FALSE~and^BOOLEAN'VAL(1)~is^TRUE`.{}b[ 211B209]@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{{@:What is MONTH_TYPE'POS(FEB)?{{{@:1.  MONTH_TYPE'POS(FEB) is 1.{{@:2.  MONTH_TYPE'POS(FEB) is 2.{}Please press 1 or 2, or B to go back.[12122213B210]@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{{%You're right!~ The positions are numbered from zero, so FEB is in position 1,{and MONTH_TYPE'POS(FEB) is 1.{}q[ 214B211Q211]@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{{No, the positions are numbered from zero, so FEB is in position 1, and{MONTH_TYPE'POS(FEB) is 1.{}q[ 214B211Q211]While^POS~and^VAL~convert to and from integers, the attributes^IMAGE~and^VALUE`{convert to and from STRINGs.  They work with any discrete types, and are useful{with integer types as well as enumeration types.  For example,{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{{  ^RAINBOW_COLOR'VALUE("RED")~@&is^RED`{  ^RAINBOW_COLOR'VALUE("yellow")~@#is^YELLOW`{  ^TRAFFIC_LIGHT_COLOR'IMAGE(AMBER)~is^"AMBER"`{{  ^INTEGER'VALUE("123")~is^ 123`{  ^INTEGER'IMAGE(123)~  is^" 123"`{  ^INTEGER'IMAGE(-123)~ is^"-123"`{{If I is an INTEGER, we can write^PUT(INTEGER'IMAGE(I));~without having to{instantiate INTEGER_IO.  However, this won't work for type FLOAT, only for{discrete types. ^VALUE~will raise a CONSTRAINT_ERROR if the STRING can't be{converted to the discrete type.  For example, taking^INTEGER'VALUE("12X3")~or{%RAINBOW_COLOR'VALUE("CHARTREUSE")~will normally display CONSTRAINT_ERROR on the{screen and stop the program.{}b[ 215B211]For any discrete type, the attributes^FIRST~and^LAST~are also available.{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{  ^RAINBOW_COLOR'FIRST~@%is^RED`{  ^TRAFFIC_LIGHT_COLOR'LAST~is^GREEN`{{A program can use these attributes with INTEGER to determine the size of{integers on the host computer.  For example, if your PC Ada has 16-bit 2's{complement integers, while a mainframe Ada uses 32-bit 2's complement, then{{@#^INTEGER'FIRST~is^-32_768~on your PC and^-2_147_483_648~on the mainframe.{@#^INTEGER'LAST~ is ^32_767~on your PC and^ 2_147_483_647~on the mainframe.{{Most attributes may also be used with subtypes:{@1subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@0^DAY_SUBTYPE'FIRST~is^1`{@0^DAY_SUBTYPE'LAST~ is^31`{{There are two subtype definitions involving^LAST~built into the Ada language:{@-^subtype POSITIVE is INTEGER range 1 .. INTEGER'LAST;`{@-^subtype NATURAL  is INTEGER range 0 .. INTEGER'LAST;`{}b[ 216B214]More attributes are discussed in the Advanced Topics section.  In summary,{%discrete type~means any integer or enumeration type.  (The only integer type{we've learned about so far is the standard INTEGER.){{@&^POS~converts from a discrete type to an integer.{@&^VAL~converts from an integer to a discrete type.{@&^IMAGE~converts from a discrete type to STRING.{@&^VALUE~converts from STRING to a discrete type.{@&^FIRST~and^LAST~take no parameter and give a discrete type.{@&^SUCC~and^PRED~take a discrete type and give the same discrete type.{{{@'Also remember that a type name followed by^'~denotes an^attribute`:{@9PUT(%CHARACTER'`VAL(7)); -- beep{{@0A type name followed by^( )~denotes^conversion`:{@?G := F +^FLOAT(`I%)`;{{@,And a type name followed by^'( )~denotes^qualification`:{@:DISPLAY(%RAINBOW_COLOR'(`RED%)`);{}b[ 217B215]@*1.  RAINBOW_COLOR'FIRST@-5.  RAINBOW_COLOR'PRED{{@*2.  RAINBOW_COLOR'IMAGE@-6.  RAINBOW_COLOR'SUCC{{@*3.  RAINBOW_COLOR'LAST@.7.  RAINBOW_COLOR'VAL{{@*4.  RAINBOW_COLOR'POS@/8.  RAINBOW_COLOR'VALUE{{{Which one of the above attributes would you use to convert from the STRING{%"Blue"~to the RAINBOW_COLOR^BLUE`?{}Please press 1, 2, 3, 4, 5, 6, 7, or 8, or B to go back.[82181219222032194221522262227223B216]%You're right!~ The attribute^VALUE~converts from STRING to a discrete type.{{@5^RAINBOW_COLOR'VALUE("Blue")~is^BLUE`.{}q[ 224B217Q217]No,^FIRST~and^LAST~take no parameter and return a discrete type:{{@)^RAINBOW_COLOR'FIRST~is^RED~and^RAINBOW_COLOR'LAST~is^VIOLET`.{{You want to convert from a STRING parameter to a discrete type.{}q[ 224B217Q217]No,^IMAGE~converts from a discrete type to STRING:{{@5^RAINBOW_COLOR'IMAGE(BLUE)~is^"BLUE"`.{{You want to convert from STRING to a discrete type.{}q[ 224B217Q217]No,^POS~converts from a discrete type to an integer:{{@8^RAINBOW_COLOR'POS(BLUE)~is^4`.{{You want to convert from STRING to a discrete type.{}q[ 224B217Q217]No,^PRED~and^SUCC~take a discrete type parameter and return the same discrete{type.{{  ^RAINBOW_COLOR'PRED(BLUE)~is^GREEN~and^RAINBOW_COLOR'SUCC(BLUE)~is^INDIGO`.{{You want to convert from STRING to a discrete type.{}q[ 224B217Q217]No,^VAL~converts from an integer to a discrete type.{{@8^RAINBOW_COLOR'VAL(4)~is^BLUE`.{{You want to convert from STRING to a discrete type.{}q[ 224B217Q217]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{%>  OPERATORS, CONTROL CONSTRUCTS, AND`{@%^ASSIGNMENT 2~@9Advanced Topics{}b[ 225B217]@COPERATORS{{The four basic arithmetic operators,^+`,^-`,^*`, and^/`, can be used with any{integer or floating point type.  (We'll learn about fixed point types in the{Advanced Topics section.)  The exponentiation operator,^**`, takes a base of{type INTEGER or FLOAT, and an exponent of subtype NATURAL.  It returns the same{type as the base.  Although FLOAT ** FLOAT isn't part of the Ada language, a{vendor may supply a math package with an Ada compiler to increase its sales{appeal.  If the math package includes a function "**" to raise a FLOAT base to{a FLOAT exponent, then our programs can^with~and^use~the package and then use{%**~between two FLOATs.  (Similarly, EXP, LOG, and the trig functions don't{come with Ada, but the vendor may supply them in a math package.){{The six^relational operators~are:{{%<~ less than@1^>~ greater than@1^=~ equal to{{%<=~less than or equal to@%^>=~greater than or equal to@%^/=~not equal to{{Five of these are the same as in Basic and Pascal, but the Ada symbol for "not{equal to" is^/=`, because^<>~means^box`.  The relational operators compare two{objects of the same type, and return a result of type BOOLEAN.{}b[ 226B224]All of the above operators are used^between~two objects (e.g.,^B := A + B;`).{Of course,^+~and^-~may also be^unary~operators (%B := +A;  A := -A;`).{{The operators^and`,^or`, and^xor~are used between two BOOLEAN objects, and^not~is{a unary BOOLEAN operator.  Naturally,^xor~is the exclusive or: ^A xor B~is TRUE{if either A or B is TRUE, but not if both are TRUE.{{The numeric operator^abs~takes the absolute value of an INTEGER or FLOAT.{Since^abs~is a unary operator like^-`, we can write^B := abs A;`.  We may, but{don't have to, use parentheses and write^B := abs(A);`.{{When used between two integers,^/~gives only the integer part of the quotient.{Thus^9/4~is 2.  The operators^mod~(modulo) and^rem~(remainder) are very similar{to each other, and are used between two integers to give only the remainder in{division.  For example,^9 mod 4~is 1.  For positive parameters,^mod~and^rem~are{the same.  But with negative parameters,^mod~gives the sign of the denominator{while^rem~gives the sign of the numerator.  Many programmers simply ignore^rem`{and use^mod~exclusively.{{The operator^&~concatenates arrays, so we'll discuss it later.  We'll learn{that a STRING is one type of array (an array of CHARACTERs), so^&~can{concatenate STRINGs.{}b[ 227B225]@BRANGE TESTS{{The reserved word^in~tests if something is inside a range, and returns a{BOOLEAN result.  For example, if LOWER, UPPER, and X are declared as FLOATs, we{need not write{{@0^if X >= LOWER and X <= UPPER then~...^end if;`{{This can be expressed more clearly as{{@3^if X in LOWER .. UPPER then~...^end if;`{{We can also write^not in`.  Thus^X not in LOWER .. UPPER~is a clear way of{expressing^X < LOWER or X > UPPER`.{{A subtype may be substituted for the range to the right of^in`.  If DAY_SUBTYPE{is defined as a subtype of INTEGER, and D is an INTEGER, then we can write{%D in DAY_SUBTYPE`.{}b[ 228B226]If we have the following declarations:{{@=B@': BOOLEAN;{@=A, X, Y : CHARACTER;{{then which^one~of the following is^illegal`?{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{}Please press 1, 2, or 3, or B to go back.[122922303231B227]@=B@': BOOLEAN;{@=A, X, Y : CHARACTER;{{{@6^1.@$B := X <> Y;`{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{{{%You're right!~ Number 1 is illegal because^<>~should be^/=`.{}q[ 232B228Q228]@=B@': BOOLEAN;{@=A, X, Y : CHARACTER;{{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{{{No, number 2 is legal.  The reserved word^in~tests to see if A is within the{range X to Y.  It returns a BOOLEAN result, which is stored in B.{}q[ 232B228Q228]@=B@': BOOLEAN;{@=A, X, Y : FLOAT;{{{@71.@$B := X <> Y;{{@72.@$B := A in X .. Y;{{@73.@$B := A = X and X = Y;{{{No, number 3 is legal.  Parentheses aren't necessary here, but it's the same as{if we had written{{@;B := (A = X) and (X = Y);{{In two places^=~returns a BOOLEAN result.  Then^and~takes the two BOOLEAN{results and also returns a result of type BOOLEAN.  That final result is then{stored in B.{}q[ 232B228Q228]@<THE SHORT CIRCUIT FORMS{{Suppose that^N~(for numerator) and^D~(for denominator) are FLOATs, and we want{to execute a block of code if the quotient is 10.0 or greater.  We could write{{@:^if N/D >= 10.0 then`{@>-----;{@>-----;  (block of code){@>-----;{@:^end if;`{{However, we realize that if^D~is 0.0, the program will raise a NUMERIC_ERROR or{CONSTRAINT_ERROR trying to compute^N/D`.  If the denominator is zero, we{consider the quotient to be very large, so we want to execute the block of code{when^D~is zero.  Our second attempt might be{{@9if^D = 0.0 or N/D >= 10.0~then{@<-----;{@<-----;  (block of code){@<-----;{@9end if;{}b[ 233B228]@9if^D = 0.0 or N/D >= 10.0~then{@<-----;{@<-----;  (block of code){@<-----;{@9end if;{{Here we^hope~that^N/D~won't be evaluated if^D~is zero.  We figure that the{compiler should be smart enough to know that if the expression before^or~is{TRUE, then the whole expression must be TRUE, so the expression to the right of{%or~needn't be evaluated.  However, there's no guarantee that the compiler will{write code to skip the evaluation of the second expression when the first is{TRUE.  An optimizing compiler just might, for some unknown reason, even decide{that the expression on the right should be evaluated first.{{However, with the form^or else`, Ada can bypass (or "short circuit") evaluating{the expression on the right when the one on the left is true:{{@6if D = 0.0^or else~N/D >= 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6end if;{}b[ 234B232]@6if D = 0.0^or else~N/D >= 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6end if;{{Ada guarantees that the expression to the left of^or else~will be evaluated{first.  If this expression is TRUE, the entire expression must be TRUE, and{it's guaranteed that the second expression won't be evaluated.  If the first{expression is FALSE, then of course the second expression must be evaluated to{determine if the entire expression is TRUE.  Thus the code above will never try{to divide by zero.  If^D~is zero, the expression on the left is TRUE.  The{expression on the right won't be evaluated in that case.{{There's another "short circuit" form called^and then`.  If the expression to{the left of^and then~is FALSE, the whole expression must be FALSE, and the{expression on the right won't be evaluated.  If the expression on the left is{TRUE, then the expression on the right must be evaluated to determine the value{of the entire expression.  Suppose this time that we want to execute a block of{code if^N/D~is^less than~10.0.  If the denominator is zero, we consider the{quotient to be very large, and we don't want to execute the block of code in{that case.  We can write the following:{}b[ 235B233]@6if D /= 0.0^and then~N/D < 10.0 then{@9-----;{@9-----;  (block of code){@9-----;{@6end if;{{Again this protects us from trying to divide by zero.  If^D~is zero, the{expression on the left is FALSE.  The second expression won't be evaluated in{that case.{{Don't use the short circuit forms where the standard^and~and^or~will do.  The{short circuit forms prevent certain compiler optimizations by requiring the{expression on the left to be evaluated first.{{After we discuss arrays, we'll see how the short circuit forms can prevent us{from using out-of-range subscripts.  And when we learn about access types,{we'll see how the short circuit forms can keep us from dereferencing a null{pointer.  That means trying to access "the object pointed to" when there's no{such object.{{Remember,^and then~evaluates the second expression only if the first expression{is TRUE;^or else~evaluates the second expression only if the first is FALSE.{}b[ 236B234]Assume that^N~has been declared^FLOAT`, and that our program^with`s and^use`s a{math package with a square root function called^SQRT`.  Naturally, we don't want{to call^SQRT~with a negative parameter.  Which of the following would be more{appropriate?{{{@+1.@$if N >= 0.0^and then~SQRT(N) > 1.618 then ...{{@+2.@$if N >= 0.0^or else~ SQRT(N) > 1.618 then ...{}Please press 1 or 2, or B to go back.[12372238B235]@*^1.@$if N >= 0.0 and then SQRT(N) > 1.618 then ...`{{@+2.@$if N >= 0.0 or else  SQRT(N) > 1.618 then ...{{{%You're right!~ We want the second expression to be evaluated only if the first{expression is TRUE, so we use^and then`.{}q[ 239B236Q236]@+1.@$if N >= 0.0 and then SQRT(N) > 1.618 then ...{{@+2.@$if N >= 0.0 or else  SQRT(N) > 1.618 then ...{{{No, we want the second expression to be evaluated only if the first expression{is TRUE, so we use^and then`.{}q[ 239B236Q236]@?CONTROL CONSTRUCTS{{You're almost ready to write your own Ada program in an Outside Assignment, but{first we need to discuss the control constructs.{{Ada encourages structured programming by providing control constructs such as{{@9block^if`s with^elsif`s and^else`{@8^while~loops{@8^for~loops{@8^case~statements{{Ada also provides a^goto~statement, but it's seldom if ever needed.  That's{because the constructs above handle the flow of control more clearly, making{the program easier to read.  With the constructs above, we know how control{reaches each statement.  When^goto`s are used, there can be many paths to a{statement, and we're not sure how control got there.{{Let's look at the above control constructs, and the^goto~statement, one at a{time.  Discussion of the^declare~statement and Ada "blocks" is postponed until{we cover exception handlers.{}b[ 240B236]@ATHE "IF" BLOCK{{@9^if~A >= B and C = A + D^then`{@=-----;{@=-----;  (block of code){@=-----;{@9^end if;`{{In Ada, every^if~introduces a block of code that ends with^end if;`.  There are{no exceptions; every^if~always has an^end if;`.  The condition is followed by{%then`, and it can be any expression with a BOOLEAN result.  The above example{is valid if A, B, C, and D are suitably declared.  Each statement in the block{of code, including the last, has a semicolon.  Note that^end if;~is two{reserved words, so there must be at least one space between them.  All Ada{control constructs, including^if~blocks, can be nested to any depth.{{In Pascal,^if~is designed to execute only one statement conditionally.  If{there's a whole block of statements to be executed conditionally, it has to be{enclosed with "begin ... end" so it will be considered as one statement.  In{Ada, however,^if~always starts a block of code, so "begin ... end" isn't{necessary.  The end of the block is always marked by^end if;~even if there's{just one statement in the block.{}b[ 241B239]@9^if A >= B and C = A + D then`{@<^-----;`{@<^-----;`{@<^-----;`{@9^elsif G = H + P then`{@<^-----;`{@9^elsif Q > R or S <= T then`{@<^-----;`{@<^-----;`{@9^else`{@<^-----;`{@9^end if;`{{The reserved words^elsif~and^else~are also available; note the unusual spelling{of^elsif`.  In the above example, only one of the four blocks of code will be{executed.  If^A >= B and C = A + D~is TRUE, the first block of code will be{executed and the remaining tests and blocks will be skipped.  Control will{continue after the^end if;`.  If^A >= B and C = A + D~is FALSE, then^G = H + P`{will be tested.  If it's TRUE, the second block, and only that block, will be{executed; otherwise,^Q > R or S <= T~will be tested.  If that's TRUE, the third{block will be executed; otherwise the^else~block will be executed.  If all the{tests are FALSE and there's no^else~block, then no blocks are executed.{}b[ 242B240]if A >= B and C = A + D then@6if A >= B and C = A + D then{@#-----;@L-----;{@#-----;@L-----;{@#-----;@9^THESE~@,-----;{elsif G = H + P then@)^<=@$TWO@$=>~@$else{@#-----;@:^ARE~@-if G = H + P then{elsif Q > R or S <= T then@%^EQUIVALENT!~@,-----;{@#-----;@Lelse{@#-----;@Oif Q > R or S <= T then{else@W-----;{@#-----;@R-----;{end if;@Qelse{@[-----;{@Xend if;{@Uend if;{@Rend if;{{As shown,^elsif~is equivalent to^else~plus^if~...^end if;`.  Although the two{program segments above are equivalent, the one on the left is much clearer.{The example on the left doesn't require multiple^end if;`s at the bottom, and{the indentation emphasizes that only one of the four blocks of code will be{executed.{}b[ 243B241]@>D, N : INTEGER := 1;{@>...{@>if D = 0 then{@AONE;{@>elsif N/D = 1 then{@ATWO;{@>elsif D = 1 then{@ATHREE;{@>else{@AFOUR;{@>end if;{{In this segment of code, which procedure(s) will be called?{{@21.  Procedure ONE will be called.{@22.  Procedure TWO will be called.{@23.  Procedure THREE will be called.{@24.  Procedure FOUR will be called.{@25.  Procedures TWO and THREE will be called.{}Please press 1, 2, 3, 4, or 5, or B to go back.[22441245324642475248B242]@>D, N : INTEGER := 1;{@>...{@>if D = 0 then{@AONE;{@=^elsif N/D = 1 then`{@@^TWO;`{@>elsif D = 1 then{@ATHREE;{@>else{@AFOUR;{@>end if;{{%You're right!~ The first test, D = 0, is FALSE, so the second test is made.{N/D = 1 is TRUE, so TWO is called.  Since only one block of code is executed in{an^if~block, the remaining tests are not done.{}q[ 249B243Q243]@>D, N : INTEGER := 1;{@>...{@>if D = 0 then{@AONE;{@>elsif N/D = 1 then{@ATWO;{@>elsif D = 1 then{@ATHREE;{@>else{@AFOUR;{@>end if;{{No, both D and N are initialized to 1, so the first test, D = 0, is FALSE and{the second test is made.  The block that's executed is the first block{following a test that's TRUE.{}q[ 249B243Q243]@>D, N : INTEGER := 1;{@>...{@>if D = 0 then{@AONE;{@>elsif N/D = 1 then{@ATWO;{@>elsif D = 1 then{@ATHREE;{@>else{@AFOUR;{@>end if;{{No, both D and N are initialized to 1, so the second test, N/D = 1, is TRUE.{The block that's executed is the^first~block following a test that's TRUE.{Once a block is executed, no further tests in that^if~block are made.  Thus,{THREE isn't called even though D = 1 is TRUE.{}q[ 249B243Q243]@>D, N : INTEGER := 1;{@>...{@>if D = 0 then{@AONE;{@>elsif N/D = 1 then{@ATWO;{@>elsif D = 1 then{@ATHREE;{@>else{@AFOUR;{@>end if;{{No, both D and N are initialized to 1, so the second test, N/D = 1, is TRUE.{The block that's executed is the first block following a test that's TRUE.  The{%else~block is executed only if all the tests are FALSE.{}q[ 249B243Q243]@>D, N : INTEGER := 1;{@>...{@>if D = 0 then{@AONE;{@>elsif N/D = 1 then{@ATWO;{@>elsif D = 1 then{@ATHREE;{@>else{@AFOUR;{@>end if;{{No, although N/D = 1 and D = 1 are both TRUE, only^one~block of code in an^if`{block is executed.  The block that's executed is the^first~block following a{test that's TRUE.{}q[ 249B243Q243]@A"WHILE" LOOPS{{@>^while~I < 10^loop`{@B-----;{@B-----;{@B-----;{@>^end loop;`{{The^while~loop first evaluates the BOOLEAN expression (%I < 10~in this example).{If it's FALSE, the block of code isn't executed at all, and execution continues{after the^end loop;`.  If it's TRUE, the block of code is executed and then the{BOOLEAN condition is again evaluated.  If the condition is still TRUE, the{block is executed again and the BOOLEAN expression is evaluated again, and so{forth.  When the BOOLEAN expression becomes FALSE, the block of code is skipped{and execution continues after the^end loop;`.{}b[ 250B243]To create an "infinite loop," it isn't necessary to write^while TRUE loop`.  We{simply write^loop`, as follows:{{@B^loop`{@F-----;{@F-----;{@F-----;{@B^end loop;`{{Ada doesn't have a "repeat ... until" loop, with the test at the bottom.{However, we can create a loop that's equivalent to a "repeat ... until" loop by{using an infinite loop with an^exit~statement, to be covered very soon.{{}b[ 251B249]@C"FOR" LOOPS{{@(^for IX in 1 .. 10 loop~@'^for IX in reverse 1 .. 10 loop`{@+^-----;~@7^-----;`{@+^-----;~@7^-----;`{@(^end loop;~@4^end loop;`{{Here are two sample^for~loops.  We need not declare the index (%IX~in these{examples) in the declarative region of the program; an index of a^for~loop{declares itself.  In these examples,^IX~comes into existence at the^for`{statement and goes out of existence at^end loop;~the index isn't available{outside the loop.  If the name^IX~happens to be used in the declarative region,{it's a different^IX`.  Inside the loop^IX~refers to the index; there the name^IX`{is said to^hide~any^IX~that might be mentioned in the declarative region.{{The index variable may not be modified.  In these examples,^IX~may not appear{on the left side of an assignment statement, etc.{{In the first example above, the block of statements is executed ten times, with{IX equal to 1, then 2, then 3, etc., up to 10.  In the second example, IX{starts at 10 and counts down to 1.  Note that the range is still written{%1 .. 10`, but the keyword^reverse~precedes the range.{}b[ 252B250]The index of a^for~loop can have any discrete type (integer or enumeration{type).  It can't be of type FLOAT.  For example, if we write{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{{then we can write^for IX in RED .. BLUE loop`, and the compiler will know that{%IX~must be of type RAINBOW_COLOR.  Similarly, the type of^IX~will be{TRAFFIC_LIGHT_COLOR if we write^for IX in RED .. AMBER loop`.  But the compiler{can't handle^for IX in RED .. GREEN loop~because of the ambiguity.  In this{case we have to specify the type.  For example, we could write either of these:{@1^for IX in RAINBOW_COLOR'(RED) .. GREEN loop`{@/^for IX in RAINBOW_COLOR range RED .. GREEN loop`{{Because the index can have any discrete type, there's no STEP clause in Ada.{One might increment an INTEGER index by 2, but we couldn't add 2 to RED.  For{uniformity, no STEP clause is available, even if the index type is INTEGER.{{Ranges may contain expressions.  If A, B, C, and D are INTEGER variables, we{can say^for I in A + B .. C + D loop~or^for I in reverse A + B .. C + D loop`.{In both cases the range is null if C + D is less than A + B.  That won't cause{an error; the loop is simply skipped when the range is null.{}b[ 253B251]If we have{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#J : INTEGER := 5;{{which one of these statements is^illegal`?{{{@81.  for I in -J .. J loop{{@82.  for I in J .. VIOLET loop{{@83.  for I in VIOLET .. RED loop{}Please press 1, 2, or 3, or B to go back.[225412553256B252]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#J : INTEGER := 5;{{@81.  for I in -J .. J loop{{@7^2.  for I in J .. VIOLET loop`{{@83.  for I in VIOLET .. RED loop{{{%You're right!~ Number 2 is illegal because the expressions before and after the{"%..`" must be of the same type.{}q[ 257B253Q253]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#J : INTEGER := 5;{{@81.  for I in -J .. J loop{{@82.  for I in J .. VIOLET loop{{@83.  for I in VIOLET .. RED loop{{{No, number 1 is legal.  The expressions on both sides of^..~have the same type.{%I~will be of type INTEGER and will take 11 values, from -5 to 5.{}q[ 257B253Q253]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#J : INTEGER := 5;{{@81.  for I in -J .. J loop{{@82.  for I in J .. VIOLET loop{{@83.  for I in VIOLET .. RED loop{{{No, number 3 is legal.  The expressions on both sides of^..~have the same type.{The loop will be skipped because RED is less than VIOLET, giving a null range.{But the syntax is legal.  To make^I~start at VIOLET and count down to RED, we{would write{{@6for I in reverse RED .. VIOLET loop{}q[ 257B253Q253]@>THE "EXIT" STATEMENT{{@)for I in 1 .. 10 loop@,for I in 1 .. 10 loop{@,J := 0;@:J := 0;{@,loop@=loop{@/J := J + 1;@6J := J + 1;{@.^if A(I, J) = 0 then`{@1^exit;~@7^exit when A(I, J) = 0;`{@.^end if;`{@,end loop;@8end loop;{@,B(I) := J;@7B(I) := J;{@)end loop;@8end loop;{{The statement^exit;~exits the innermost loop.  In the example at the left,{%exit;~transfers control to the statement^B(I) := J;`.  Since^exit;~is often the{only statement in an^if~block,^exit when~is available to abbreviate an^if~block{with^exit;~as its only statement.  The two examples above are equivalent.{{Although^exit;~can appear anywhere inside any kind of loop, well-structured{Ada programs use only^exit when`, and then only as the last statement of an{otherwise infinite loop, as shown at the right above.  This simulates a{"repeat ... until" loop, which isn't directly available in Ada.{}b[ 258B253]@6^OUTER:`{@6^for I in 1 .. 10 loop`{@:J := 0;{@:loop{@=J := J + 1;{@<^exit OUTER when A(I, J) = 0;`{@:end loop;{@:B(I) := J;{@6^end loop OUTER;`{@7K := J;{{An^exit~statement can exit other than the innermost loop by^naming~the loop to{be exited.  In this example, the^for~loop is named^OUTER`.  A loop name is any{Ada identifier, and is followed by a colon.  Of course,^OUTER:~could have been{placed on the same line as the^for~statement.  When a loop is named, the^end`{%loop~statement must repeat the name of the loop.  The^exit~statement can then{name the loop to be exited, as in^exit OUTER;~or^exit OUTER when A(I, J) = 0;`.{In this example, the^exit~statement transfers control to the statement^K := J;`,{not to^B(I) := J;`.{{Well-structured programs don't use^exit~to leave any loop except the innermost{loop.  The above example isn't well-structured.{}b[ 259B257]@@LABELS AND GOTOS{{@7OUTER:{@7for I in 1 .. 10 loop{@:J := 0;{@:loop{@=J := J + 1;{@=exit OUTER when A(I, J) = 0;{@:end loop;{@:B(I) := J;{@7end loop OUTER;{@7K := J;{{Although an Ada loop name looks exactly like a Pascal label,^OUTER:~is^not~a{label, and the program can't^goto OUTER`.  An Ada label looks like this:{{@B^<< JAIL >>`{{The^<<~...^>>~makes the label very conspicuous, whether it's on the same line{as a statement or on a line by itself.  The program can then say^goto JAIL;`.{Like all reserved words,^goto~can't contain a space.  Well-structured Ada{programs don't need^goto`s and labels, so their use is very rare.{}b[ 260B258]@8I_LOOP:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_LOOP:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_LOOP;{@EL := J;{@Bend loop I_LOOP;{@BM := J;{{{In the program segment above, which statement will be executed after^exit;`?{{@;1.  L := J;{{@;2.  M := J;{{@;3.  for I in 1 .. 10 loop{}Please press 1, 2, or 3, or B to go back.[126122623263B259]@8I_LOOP:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_LOOP:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_LOOP;{@D^L := J;`{@Bend loop I_LOOP;{@BM := J;{{{%You're right!~ When used without a name,^exit;~leaves the innermost loop, so{the next statement executed is^L := J;`.{}q[ 264B260Q260]@8I_LOOP:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_LOOP:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_LOOP;{@EL := J;{@Bend loop I_LOOP;{@BM := J;{{{No, when used without a name,^exit;~leaves the^innermost~loop.{}q[ 264B260Q260]@8I_LOOP:@#for I in 1 .. 10 loop{@EJ := 0;{@8J_LOOP:@&loop{@HJ := J + 1;{@Hexit;{@Eend loop J_LOOP;{@EL := J;{@Bend loop I_LOOP;{@BM := J;{{{No, when used without a name,^exit;~leaves the innermost loop.  The next{statement executed will be the first statement after the end of the innermost{loop.{}q[ 264B260Q260]@>THE "CASE" CONSTRUCT{{%case C is~@7In this example, assume that^C~is of type{  ^when '*' =>~@2CHARACTER.  The expression being tested (%C`),{@%^-----;~@4must have a discrete type: integer or{@%^-----;~@4enumeration type.  The^case~construct must{  ^when '#' | '$' =>~@,handle all possible values, but^when others~is{@%^-----;~@4available.  If no action is desired for{@%^-----;~@4characters not mentioned, we can write^when`{@%^-----;~@3^others => null;`.  The Ada statement^null;~does{  ^when '0' .. '9' =>~@+nothing.  Note that the vertical bar can be{@%^-----;~@4used to apply several cases to one block of{  ^when 'A'..'Z' | 'a'..'z' =>~  code, and that ranges can be used.  Here, if^C`{@%^-----;~@4is '*', the first block is executed; if it's{@%^-----;~@4'#' or '$', the second block is executed.  If{@%^-----;~@4it's a digit, the third block is executed, and{  ^when others =>~@/if it's a letter (upper or lower case), the{@%^-----;~@4fourth block is executed.  If^C~is anything{@%^-----;~@4else, the fifth (last) block of code is{%end case;~@7executed.{}b[ 265B260]case C is{@#when '*' =>@8if C = '*' then{@&-----;@=-----;{@&-----;@=-----;{@#when '#' | '$' =>@2elsif C = '#' or C = '$' then{@&-----;@=-----;{@&-----;@=-----;{@&-----;@=-----;{@#when '0' .. '9' =>@1elsif C in '0' .. '9' then{@&-----;@=-----;{@#when 'A'..'Z' | 'a'..'z' =>@(elsif C in 'A'..'Z' or C in 'a'..'z' then{@&-----;@=-----;{@&-----;@=-----;{@&-----;@=-----;{@#when others =>@5else{@&-----;@=-----;{@&-----;@=-----;{end case;@=end if;{{The two examples above are equivalent.  In both cases only one block of code{will be executed.  By the way, the symbol^=>~is read "arrow" and may not{contain a space.{}b[ 266B264]If we have{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{@#F : FLOAT range 0.0 .. 2.0;{@#R : RAINBOW_COLOR;{@#T : TRAFFIC_LIGHT_COLOR;{{then which^one~of the following program segments is^legal`?{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$when RED | GREEN =>@-when 0.0 .. 1.0 =>@+when RED =>{@'-----;@:-----;@7-----;{@$when BLUE .. VIOLET =>@*when others =>@/when others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{}Please press 1, 2, or 3, or B to go back.[326712682269B265]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{@#F : FLOAT range 0.0 .. 2.0;{@#R : RAINBOW_COLOR;{@#T : TRAFFIC_LIGHT_COLOR;{{@,1:@<2:@8^3:`{{ case R is@7case F is@3^case T is`{@$when RED | GREEN =>@-when 0.0 .. 1.0 =>@*^when RED =>`{@'-----;@:-----;@6^-----;`{@$when BLUE .. VIOLET =>@*when others =>@.^when others =>`{@'-----;@:-----;@6^-----;`{ end case;@7end case;@3^end case;`{{%You're right!~ Number 1 is illegal because it doesn't account for all possible{values of^R`, and number 2 is illegal because^F~doesn't have a discrete type.{}q[ 270B266Q266]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{@#F : FLOAT range 0.0 .. 2.0;{@#R : RAINBOW_COLOR;{@#T : TRAFFIC_LIGHT_COLOR;{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$when RED | GREEN =>@-when 0.0 .. 1.0 =>@+when RED =>{@'-----;@:-----;@7-----;{@$when BLUE .. VIOLET =>@*when others =>@/when others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{No, number 1 is illegal because it doesn't account for all the possible values{of^R`.{}q[ 270B266Q266]@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{@#type TRAFFIC_LIGHT_COLOR is (RED, AMBER, GREEN);{@#F : FLOAT range 0.0 .. 2.0;{@#R : RAINBOW_COLOR;{@#T : TRAFFIC_LIGHT_COLOR;{{@,1:@<2:@93:{{ case R is@7case F is@4case T is{@$when RED | GREEN =>@-when 0.0 .. 1.0 =>@+when RED =>{@'-----;@:-----;@7-----;{@$when BLUE .. VIOLET =>@*when others =>@/when others =>{@'-----;@:-----;@7-----;{ end case;@7end case;@4end case;{{No, number 2 is illegal because^F~doesn't have a discrete type.{}q[ 270B266Q266]@:BRIEF OVERVIEW OF FUNCTIONS{{@.procedure FUNCT_DEMO is{@1X : FLOAT := 1.2;{@1Y : FLOAT;{@0^function TWICE(DUMMY : in FLOAT) return FLOAT is`{@3^ANSWER : FLOAT;`{@0^begin`{@3^ANSWER := DUMMY * 2.0;`{@3^return ANSWER;`{@0^end TWICE;`{@.begin{@1Y := TWICE(X);{@.end FUNCT_DEMO;{{Let's look briefly at functions so we can do Outside Assignment 2; later, we'll{cover functions and procedures in detail.  Here procedure FUNCT_DEMO locally{declares a function TWICE.  TWICE can be called only from within FUNCT_DEMO:{%Y := TWICE(X);`.  The function specification gives the name (DUMMY), mode (in),{and type (FLOAT) of any formal parameters, or "dummy arguments."  For{functions, the mode of all parameters must be^in`, never^out~or^in out`.  The{function specification also gives the type being^return`ed, in this case FLOAT.{}b[ 271B266]@.procedure FUNCT_DEMO is{@1X : FLOAT := 1.2;{@1Y : FLOAT;{@1function TWICE(DUMMY : in FLOAT) return FLOAT is{@4ANSWER : FLOAT;{@1begin{@4ANSWER := DUMMY * 2.0;{@3^return ANSWER;`{@1end TWICE;{@.begin{@1Y := TWICE(X);{@.end FUNCT_DEMO;{{The function body must have^return~followed by an expression of the right type.{In well-structured functions, this is the last statement before^end`.  We don't{return a value by placing the name of the function in an assignment statement,{as in Fortran.  Of course, function TWICE could be written more simply as{{@0function TWICE(DUMMY : in FLOAT) return FLOAT is{@0begin{@3return DUMMY * 2.0;{@0end TWICE;{}b[ 272B270]@)procedure FUNCT_DEMO is{@,X : FLOAT := 1.2;{@,Y : FLOAT;{@+^function TWICE(DUMMY : in FLOAT) return FLOAT is separate;`{@)begin{@,Y := TWICE(X);{@)end FUNCT_DEMO;{{@(^separate (FUNCT_DEMO)`{@(^function TWICE(DUMMY : in FLOAT) return FLOAT is`{@)begin{@,return DUMMY * 2.0;{@)end TWICE;{{The function can be placed in a separate file and compiled later.  Here the{calling program can be compiled once, and later the function can be edited and{recompiled as often as desired. ^TWICE~is still local to^FUNCT_DEMO`.  The{phrase^separate (FUNCT_DEMO)~tells Ada that this subprogram is part of the{previously compiled unit^FUNCT_DEMO`.  It's as if the function were cut out and{"pasted" where the calling program says^function TWICE~...^is separate;`.  Ada{can still compile the call^Y := TWICE(X);~because the calling program contains{the specification of the function.{}b[ 273B271]@.OUTSIDE ASSIGNMENT 2 - EXERCISE IN ENUMERATION TYPES{{Separate compilation is the basis of our next Outside Assignment.  The function{we want you to write is completely specified by these two lines of Ada:{{@%^type TRIANGLE is (EQUILATERAL, ISOSCELES, SCALENE, NOT_A_TRIANGLE);`{@%^function TRITYPE(LEN1, LEN2, LEN3 : in INTEGER) return TRIANGLE;`{{From these two lines, it's obvious that your function must decide whether three{integers, representing the lengths of the sides of a triangle, in fact{represent an equilateral triangle, an isosceles triangle, a scalene triangle,{or no triangle at all.  (An equilateral triangle has three equal sides; an{isosceles triangle has only two equal sides.  A scalene triangle has sides of{three different lengths, and the integers -1, 0, 5 represent no triangle.){{A test driver for your function is already written, and is in the file{%TRITEST.ADA`.  A listing starts on page 10 of your printed course notes.  You{need not understand the test driver.  It's sufficient to know that if your{function passes all the tests, the message "Congratulations, you completed the{assignment!" is shown.  For any failed tests, the test driver displays the test{case, the answer from your function, and the correct answer.  This will help{you in debugging your function.{}b[ 274B272]The test driver, which is the main program, contains these declarations:{{  type TRIANGLE is (EQUILATERAL, ISOSCELES, SCALENE, NOT_A_TRIANGLE);{  function TRITYPE(LEN1, LEN2, LEN3 : in INTEGER) return TRIANGLE is separate;{{This allows you to edit and recompile your function as often as you like,{without having to recompile the test driver.  Since type^TRIANGLE~is defined in{the calling program, you should^not~define it in your function.{{To get you started, a dummy solution is given in^TRITYPE.DUM`.  You can copy it{and edit the copy to become your real solution.  It looks like this:{{@'-- Dummy solution for Outside Assignment 2{@'-- Edit to become your real solution.{@'separate (TRITEST){@'function TRITYPE(LEN1, LEN2, LEN3 : in INTEGER) return TRIANGLE is{@'begin{@*return NOT_A_TRIANGLE;{@'end TRITYPE;{{If you wish, you may compile this dummy solution before editing it.  Then{you'll see what error messages from the test driver look like.{}b[ 275B273]@'-- Dummy solution for Outside Assignment 2{@'-- Edit to become your real solution.{@&^separate (TRITEST)`{@&^function TRITYPE(LEN1, LEN2, LEN3 : in INTEGER) return TRIANGLE is`{@&^begin`{@*return NOT_A_TRIANGLE;{@&^end TRITYPE;`{{When you do edit the function, you'll probably want to remove or change the{first two comment lines.  Don't change the lines^highlighted~above.  You may{want to create a new variable of type TRIANGLE, and return that variable{instead of the constant NOT_A_TRIANGLE at the end of your function:{{@'separate (TRITEST){@'function TRITYPE(LEN1, LEN2, LEN3 : in INTEGER) return TRIANGLE is{@)^ANSWER : TRIANGLE;`{@'begin{@*if ... end if;{@)^return ANSWER;`{@'end TRITYPE;{{However, that's not the only way to solve the problem, just a suggestion.{}b[ 276B274]Here are the steps to follow for Outside Assignment 2.  They're also in your{printed course notes on page 12:{{1.  Compile the test driver TRITEST.ADA.  Also, make a copy of the dummy{@$solution by typing^COPY TRITYPE.DUM TRITYPE.ADA`.  You need do this step{@$only once.{{2.  Edit TRITYPE.ADA to become your real solution.  You may skip this step the{@$first time through, to see error messages from the test driver.{{3.  Compile your solution TRITYPE.ADA.  If the compiler finds errors, go back{@$to step 2.{{4.  Link with the name of the main program TRITEST.  Then execute.  If the test{@$driver displays error messages, go back to step 2.{{5.  When the message "Congratulations, you completed the assignment!" is{@$displayed, you'll have a chance to compare your solution with ours.{}b[ 277B275]Remember that a function can't change the values of its parameters (in this{case, LEN1, LEN2, and LEN3), because function parameters are always of mode^in`.{{This assignment should be a simple exercise in enumeration types and the{control constructs.  Our solution easily fits on one screen.  If you find your{solution getting long and difficult, you should probably think through the{problem again.  See if there's a simple way to test for the four possible{answers.{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 2.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 278B276]@-^Congratulations on Completing Outside Assignment 2!`{{Our solution is in^TRITYPE.ANS`.  It looks like this:{{-- Our solution to Outside Assignment 2:{separate (TRITEST){function TRITYPE(LEN1, LEN2, LEN3 : in INTEGER) return TRIANGLE is{@#ANSWER : TRIANGLE;{begin{@#if LEN1 + LEN2 <= LEN3  or LEN1 + LEN3 <= LEN2  or LEN2 + LEN3 <= LEN1  then{@&ANSWER := NOT_A_TRIANGLE;{@#elsif  LEN1 = LEN2  and  LEN2 = LEN3  then{@&ANSWER := EQUILATERAL;{@#elsif  LEN1 = LEN2  or  LEN2 = LEN3  or  LEN1 = LEN3  then{@&ANSWER := ISOSCELES;{@#else{@&ANSWER := SCALENE;{@#end if;{@#return ANSWER;{end TRITYPE;{}b[ 279B277]Note that it isn't necessary to include tests for sides <= 0, because if any{side <= 0, one of the three tests in the following would have to catch that:{{if  LEN1 + LEN2 <= LEN3  or  LEN1 + LEN3 <= LEN2  or  LEN2 + LEN3 <= LEN1  then{@#ANSWER := NOT_A_TRIANGLE;{{However, most students include tests for sides <= 0, so if you did, don't feel{bad.  It doesn't do any harm.{{You must have realized by now that it's impossible to draw a triangle with{sides 1, 2, and 3.  The sum of any two sides must be greater than the third.{{There are many correct ways to solve this problem.  Some students make copies{of the three sides and sort them first.  Some initialize ANSWER to SCALENE in{the declarative region and omit the code{{@=else{@@ANSWER := SCALENE;{{If you saw the message "Congratulations, you completed the assignment!" you may{consider your solution correct.  Let's go on to discuss Records and Arrays.{}b[ 280B278]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@9^>  RECORDS, ARRAYS, AND ASSIGNMENT 3`{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 281B279]@DRECORDS{{A^record~lets us group several declarations together and refer to them as one:{{@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{@%subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@$^type DATE is`{@'^record`{@*^DAY@#: DAY_SUBTYPE;~  -- Naturally, DAY_SUBTYPE and{@*^MONTH : MONTH_TYPE;~@#-- MONTH_TYPE must be defined{@*^YEAR  : INTEGER;~@&-- before type DATE is defined.{@'^end record;`{@$^USA : DATE;`{{In this example,^USA~has three parts (called "fields"): ^USA.DAY`,^USA.MONTH`,{and^USA.YEAR`.  The fields of a record can be of any type, including other{records.  Here^USA.DAY~is of^type~INTEGER,^USA.MONTH~is of type MONTH_TYPE, and{%USA.YEAR~is of type INTEGER.  The parts of^USA~may be referenced separately:{{@>^USA.DAY@#:= 4;`{@>^USA.MONTH := JUL;`{@>^USA.YEAR  := 1776;`{}b[ 282B280]@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{@%subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@$^type DATE is`{@'^record`{@*^DAY@#: DAY_SUBTYPE;`{@*^MONTH : MONTH_TYPE;`{@*^YEAR  : INTEGER;`{@'^end record;`{@$^USA : DATE;`{{However,^USA~can also be referenced as one object.  For example, we could have{assigned all three fields in one statement: ^USA := (4, JUL, 1776);`.  Here the{object on the left is of type DATE, and the object on the right is called an{%aggregate`.  The aggregate fits the type DATE because it contains an INTEGER, a{MONTH_TYPE, and another INTEGER.  This aggregate is said to use^positional`{notation because its three parts appear in the same order as the three parts of{the record definition:  first DAY, then MONTH, then YEAR.{{We can specify the parts of an aggregate in any order if we use^named~notation:{%USA := (MONTH => JUL, DAY => 4, YEAR => 1776);`.  (The symbol^=>~is read "arrow"{and may not contain a space.)  Using named notation often improves program{readability, especially if the names of the fields are well chosen.{}b[ 283B281]@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{@%subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@$^type DATE is`{@'^record`{@*^DAY@#: DAY_SUBTYPE;`{@*^MONTH : MONTH_TYPE;`{@*^YEAR  : INTEGER;`{@'^end record;`{@$^USA : DATE;`{{We can switch from positional to named notation in an aggregate.  But once we{use named notation, the compiler loses track of position, so we can't switch{back to positional.  For example, the following is^legal`:{{@3^USA := (4, YEAR => 1776, MONTH => JUL);`{{But the following is^illegal~because positional notation can't follow named:{{@3USA := (4, YEAR => 1776, JUL); -- illegal{{Record discriminants and record variants will be discussed in the Advanced{Topics Section.{}b[ 284B282]@$procedure RECORD_EXERCISE is{@'type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{@'subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@'type DATE is{@*record{@-DAY@#: DAY_SUBTYPE;{@-MONTH : MONTH_TYPE;{@-YEAR  : INTEGER;{@*end record;{@'D1, D2, D3 : DATE; ^-- 1`{@$begin{@'D1 := (MONTH => JAN, DAY => 22, YEAR => 1983); ^-- 2`{@'D2.DAY := 22;{@'D2.MONTH := 1; ^-- 3`{@'D2.YEAR := 1983;{@'D3 := D2; ^-- 4`{@$end RECORD_EXERCISE;{{Which commented line in the above program is^illegal`?{}Please press 1, 2, 3, or 4, or B to go back.[3285128622874288B283]@&^D2.MONTH := 1;  -- 3`{{%You're right!~ This statement is illegal, because the types are mixed.{%D2.MONTH~is of type MONTH_TYPE, and^1~is an integer.{}q[ 289B284Q284]@'D1, D2, D3 : DATE;  -- 1{{No, this statement is legal, because several objects may be declared in one{statement, if the objects are separated by commas.{}q[ 289B284Q284]@'D1 := (MONTH => JAN, DAY => 22, YEAR => 1983);  -- 2{{No, this statement is legal, because the fields within the aggregate may appear{in any order when named notation is used.{}q[ 289B284Q284]@'D3 := D2;  -- 4{{No, this statement is legal, because^D3~and^D2~both have the same type:^DATE`.{An entire record can be assigned with one statement.{}q[ 289B284Q284]@EARRAYS{{To declare an array in Ada, we specify the^type and range of the subscript`,{followed by the^type of the elements~of the array.  The subscript can have any{discrete type (integer or enumeration), and the elements of the array can be of{any type at all, including records and other arrays.  There are three ways to{declare an array in Ada.  Here are three examples of the most direct, but least{flexible, way (types RAINBOW_COLOR and DATE must be defined earlier):{{%A : array(RAINBOW_COLOR range ORANGE .. BLUE) of DATE;`{@#-- A four-element array, each element of which is a record with three parts.{@#-- The allowable subscripts are ORANGE, YELLOW, GREEN, and BLUE.  Here{@#-- A(YELLOW) is of type DATE, and A(YELLOW).YEAR is of type INTEGER.{%B : array(INTEGER range -10 .. 10) of INTEGER;`{@#-- An array of 21 INTEGERs, with INTEGER subscripts.{%C : array(0 .. 30) of FLOAT;`{@#-- Here (0 .. 30) is understood to mean (INTEGER range 0 .. 30), and we have{@#-- an array of 31 FLOATs, with INTEGER subscripts.`{{A subscript can be an expression; if I is an INTEGER, we can write^C(2*I)`.  If{a subscript is out-of-range (for example,^A(RED)~or^C(-32)`), the program will{raise a CONSTRAINT_ERROR.{}b[ 290B284]This direct method of declaring arrays is usually used to create single arrays{for table lookup, etc., where there's no need to have several arrays of the{same type.  A better way to declare an array is to specify a type name for the{array itself.  Then several objects can be declared to have that same type.{For example,{{@1^type VECTOR100 is array(1 .. 100) of FLOAT;`{@1^type VECTOR300 is array(1 .. 300) of FLOAT;`{@1^D, E, F : VECTOR100;`{@1^G, H@$: VECTOR300;`{{Here D, E, and F are all of type^VECTOR100`, so we can write^D := E;~ and assign{the entire array with one statement.  Similarly, we can write^G := H;`, but not{%G := F;`.{{The example above takes four statements.  An even better way to declare arrays{is to leave the range of the subscript unspecified with the^box~symbol,^<>`,{specifying the range when declaring the objects.  For example,{{@/^type VECTOR is array(INTEGER range <>) of FLOAT;`{@/^D, E, F : VECTOR(1 .. 100);`{@/^G, H@$: VECTOR(1 .. 300);`{}b[ 291B289]There are two errors to avoid when declaring arrays in this way.  One is to{declare a type with the box symbol for the range of the subscript, and then{fail to specify the range when declaring an object (other than a constant):{{@.^type VECTOR is array(INTEGER range <>) of FLOAT;`{@.^D1 : VECTOR := (2.3, 4.5, 4.0); -- illegal`{@/D2 :^constant~VECTOR := (2.3, 4.5, 4.0);^-- legal`{{This error is called^unconstrained array`.  Unconstrained arrays are legal in{formal parameters ("dummy arguments") of procedures and functions, and a{function can^return~an unconstrained array type.  (We'll learn about these{things later.)  But an unconstrained array is illegal when declaring a{variable, because the compiler needs to know the range of the subscript.{{The other error is to specify the range of the subscript twice: once when{declaring the type and once when declaring the object:{{@1^type VECTOR100 is array(1 .. 100) of FLOAT;`{@1^D2 : VECTOR100(1 .. 100);  -- illegal`{{Even if the two ranges agree, this is illegal and is called^doubly constrained{array`.{}b[ 292B290]Arrays may be initialized and assigned with aggregates, and both positional and{named notation may be used.  For example, arrays^A~and^B~are equal here:{{^type VECTOR5 is array(1 .. 5) of FLOAT;`{^A : constant VECTOR5 := (2.0, 4.0, 8.0, 16.0, 32.0);`{^B : constant VECTOR5 := (1 => 2.0, 2 => 4.0, 3 => 8.0, 4 => 16.0, 5 => 32.0);`{{The aggregate must fill the whole array, but the reserved word^others~is{available.  Here's an array of 500 FLOAT variables, all initialized to 0.0:{{@1^type VECTOR500 is array(1 .. 500) of FLOAT;`{@1^V1 : VECTOR500 := (others => 0.0);`{{If^others~follows named notation, it's best to qualify the aggregate with the{type name.  Here W(10) = 1.3, W(15) = -30.7, and the rest of the array is 0.0:{{@$^W : VECTOR500 := VECTOR500'(10 => 1.3,  15 => -30.7,  others => 0.0);`{{Sometimes we^must~qualify an aggregate when^others~is used with named notation;{at other times it's optional.  The rules (LRM section 4.3.2, paragraphs 4-8){are very complicated.  It's easiest always to qualify an aggregate when^others`{follows named notation, as shown above.{}b[ 293B291]In array aggregates, multiple choices can be denoted with the vertical bar (%|`),{shift-backslash on your keyboard.  In this array, the elements with odd{subscripts are TRUE, while the elements with even subscripts are FALSE:{{@)^type DECADE is array(1 .. 10) of BOOLEAN;`{@)^D1 : DECADE;`{@*...{@)^D1 := DECADE'(1 | 3 | 5 | 7 | 9 => TRUE,  others => FALSE);`{{Here we assigned to D1 with an executable statement for variety; we could also{have initialized D1 in the declarative region with the same aggregate.  Some{people read the vertical bar as "and," others as "or."  One can say, "Elements{1,^and~3, and 5, and 7, and 9 are TRUE," or one can say, "If the subscript is{1,^or~3, or 5, or 7, or 9, the array element is TRUE."{{Array aggregates may also contain ranges.  In this array, elements 1 and 6 - 10{are 1; the rest are 0.  Arrays^L1~and^L2~are equal:{{@(^type LIST15 is array(1 .. 15) of INTEGER;`{@(^L1 : LIST15 := LIST15'(1 | 6 .. 10 => 1,  others => 0);`{@(^L2 : LIST15 := (1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0);`{}b[ 294B292]%with TEXT_IO; use TEXT_IO;`{%procedure ARRAY_QUIZ is`{  ^package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;`{  ^subtype CAPITAL_LETTER is CHARACTER range 'A' .. 'Z';{  ^type SET_OF_LETTERS is array(CAPITAL_LETTER) of BOOLEAN;`{  ^VOWELS : SET_OF_LETTERS :=`{@'^SET_OF_LETTERS'('A' | 'E' | 'I' | 'O' | 'U' => TRUE,  others => FALSE);`{  ^LETTER : CAPITAL_LETTER;`{%begin`{  ^LETTER := 'E';`{  ^PUT(BOOLEAN'POS(VOWELS(LETTER)));`{%end ARRAY_QUIZ;`{{@7What will this program display?{{@71.  The program will display 1.{{@72.  The program will display 2.{{@73.  The program will display TRUE.{{@74.  The program will display E.{}Please press 1, 2, 3, or 4, or B to go back.[1295229632974298B293]%with TEXT_IO; use TEXT_IO;`{%procedure ARRAY_QUIZ is`{  ^package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;`{  ^subtype CAPITAL_LETTER is CHARACTER range 'A' .. 'Z';`{  ^type SET_OF_LETTERS is array(CAPITAL_LETTER) of BOOLEAN;`{  ^VOWELS : SET_OF_LETTERS :=`{@'^SET_OF_LETTERS'('A' | 'E' | 'I' | 'O' | 'U' => TRUE,  others => FALSE);`{  ^LETTER : CAPITAL_LETTER;`{%begin`{  ^LETTER := 'E';`{  ^PUT(BOOLEAN'POS(VOWELS(LETTER)));`{%end ARRAY_QUIZ;`{{{%You're right!~ VOWELS has 26 elements, with subscripts 'A' through 'Z'.{VOWELS(LETTER) is VOWELS('E'), which is TRUE, and since Ada defines{{@9type BOOLEAN is (FALSE, TRUE);{{and the positions are numbered starting from 0, BOOLEAN'POS(TRUE) is 1.{}q[ 299B294Q294]with TEXT_IO; use TEXT_IO;{procedure ARRAY_QUIZ is{@#package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@#subtype CAPITAL_LETTER is CHARACTER range 'A' .. 'Z';{@#type SET_OF_LETTERS is array(CAPITAL_LETTER) of BOOLEAN;{@#VOWELS : SET_OF_LETTERS :={@(SET_OF_LETTERS'('A' | 'E' | 'I' | 'O' | 'U' => TRUE,  others => FALSE);{@#LETTER : CAPITAL_LETTER;{begin{@#LETTER := 'E';{@#PUT(BOOLEAN'POS(VOWELS(LETTER)));{end ARRAY_QUIZ;{{{No.  Recall that Ada defines{{@9type BOOLEAN is (FALSE, TRUE);{{and that the positions are numbered starting with 0 for the^POS~attribute.{}q[ 299B294Q294]with TEXT_IO; use TEXT_IO;{procedure ARRAY_QUIZ is{@#package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@#subtype CAPITAL_LETTER is CHARACTER range 'A' .. 'Z';{@#type SET_OF_LETTERS is array(CAPITAL_LETTER) of BOOLEAN;{@#VOWELS : SET_OF_LETTERS :={@(SET_OF_LETTERS'('A' | 'E' | 'I' | 'O' | 'U' => TRUE,  others => FALSE);{@#LETTER : CAPITAL_LETTER;{begin{@#LETTER := 'E';{@#PUT(BOOLEAN'POS(VOWELS(LETTER)));{end ARRAY_QUIZ;{{{No.  Indeed VOWELS(LETTER) is VOWELS('E'), which is TRUE, but the program takes{the BOOLEAN'POS of VOWELS(LETTER).  Recall that the attribute^POS~converts from{a discrete type (in this case, BOOLEAN) to an integer.{}q[ 299B294Q294]with TEXT_IO; use TEXT_IO;{procedure ARRAY_QUIZ is{@#package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@#subtype CAPITAL_LETTER is CHARACTER range 'A' .. 'Z';{@#type SET_OF_LETTERS is array(CAPITAL_LETTER) of BOOLEAN;{@#VOWELS : SET_OF_LETTERS :={@(SET_OF_LETTERS'('A' | 'E' | 'I' | 'O' | 'U' => TRUE,  others => FALSE);{@#LETTER : CAPITAL_LETTER;{begin{@#LETTER := 'E';{@#PUT(BOOLEAN'POS(VOWELS(LETTER)));{end ARRAY_QUIZ;{{{No.  While LETTER is 'E', and LETTER appears inside the PUT statement, the{parameter of PUT is the BOOLEAN'POS of one element of array VOWELS{(specifically, the element whose subscript is 'E').  Recall that the^POS`{attribute always returns an integer.{}q[ 299B294Q294]In an array declaration or an array type declaration, we may totally omit the{range of the subscript (not even supplying a box), if the type or subtype of{the subscript has a reasonable number of possible values.  (We did that in the{declaration of type SET_OF_LETTERS in the last question.)  For example, in{{@#type RAINBOW_COLOR is (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET);{  ^R : array(RAINBOW_COLOR) of FLOAT;`{{we have an array of seven FLOATs, because there are seven possible values of{type RAINBOW_COLOR.  Similarly,{{@7^V : array(CHARACTER) of BOOLEAN;`{{creates an array of 128 BOOLEANs.  However,^J : array(INTEGER) of FLOAT;~is an{attempt to declare a very large array indeed!  In a case like this, we can use{a subtype in the subscript declaration:{{@1subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@0^J : array(DAY_SUBTYPE) of FLOAT;`{{This creates an array of 31 FLOATs.{}b[ 300B294]The attributes^FIRST~and^LAST`, which we've seen with discrete types, can also{be used with array types and with the array names themselves.  For example,{{@0^type MY_VECTOR is array(30 .. 33) of INTEGER;`{@0^MV : MY_VECTOR;`{@1...{@0^MV(30) := 1000;`{@0^MV(31) := 20;`{@0^MV(32) := -70;`{@0^MV(33) := -500;`{{Here^MV'FIRST~and^MY_VECTOR'FIRST~are both 30. ^MV'LAST~and^MY_VECTOR'LAST~are{both 33.  Note that^FIRST~and^LAST~refer to the subscripts, not to the values{of the array elements.  Thus^MV'FIRST~is^not~1000.  To obtain the value of the{first element, we would use^MV'FIRST~as a^subscript`. ^MV(MV'FIRST)~is 1000.{{The attribute^RANGE~is an abbreviation for^FIRST .. LAST`.  It can be used only{with array types and array names, not with discrete types.  Thus^MV'RANGE~and{%MY_VECTOR'RANGE~both mean^30 .. 33`.  We can't write^INTEGER'RANGE`, even though{we can write^INTEGER'FIRST~and^INTEGER'LAST`.  The attribute^LENGTH~is also{available: ^MV'LENGTH~and^MY_VECTOR'LENGTH~are both 4.{}b[ 301B299]@<MULTIDIMENSIONAL ARRAYS{{Ada arrays may have any number of dimensions, and the subscripts may be of{different discrete types.  For example, assuming RAINBOW_COLOR, MONTH_TYPE, and{DATE have already been defined, we can write{{@$^X : array(INTEGER range -10 .. -1, RAINBOW_COLOR range ORANGE .. BLUE,`{@.^MONTH_TYPE range FEB .. JUN) of DATE;`{{Here the first subscript is of type INTEGER and has 10 possible values, the{second subscript is of type RAINBOW_COLOR and has four possible values, and the{third subscript has type MONTH_TYPE with five possible values.  Thus we have{a three-dimensional array of 10 * 4 * 5 = 200 DATEs.  One element of the array{might be^X(-5, GREEN, APR)`; one field of that element might be{%X(-5, GREEN, APR).YEAR`.  The array in this example probably has no use, other{than demonstrating that multiple subscripts need not have the same type.{{If one subscript of a multidimensional array type is constrained, they must all{be constrained.  We can't write{{@$type RECTANGLE is array(1 .. 5, INTEGER range <>) of FLOAT;  -- illegal{}b[ 302B300]Multidimensional arrays are initialized or assigned with^nested aggregates`.  We{can create a two-dimensional array of FLOATs, initializing all 50 elements to{1.0, with^MAT : array(0 .. 9, 1 .. 5) of FLOAT := (others => (others => 1.0));`.{{Here X is a 10-by-10 array of INTEGERs.  All elements are 0, except X(4, 5),{which is 1.  We qualify the aggregate because^others~follows named notation:{{@%^type SQUARE10 is array (1 .. 10, 1 .. 10) of INTEGER;`{@%^X : SQUARE10 := SQUARE10'(@%4@%=>@#(5 => 1, others => 0),`{@B^others  =>@'(others => 0)@');`{{We initialize or assign an^array of arrays~with nested aggregates, the same as{a multidimensional array.  However, we reference a single element differently:{{ ^type SQUARE10 is array(1 .. 10, 1 .. 10) of INTEGER;`{ ^type ROW10@$is array(1 .. 10) of INTEGER;`{ ^type MAT10@$is array(1 .. 10) of ROW10;`{ ^S : SQUARE10 := (others => (others => 0)); -- S is a two-dimensional array.`{ ^M : MAT10@$:= (others => (others => 0)); -- M is an array of arrays.`{  ...{ ^S(4, 5) := 1; -- a single element of a two-dimensional array`{ ^M(4)(5) := 1; -- a single element of an array of arrays`{}b[ 303B301]The "short circuit" forms can prevent us from using array subscripts that are{out of range.  For example, if we write{{@4A : array(1 .. 10) of FLOAT;{@4I : INTEGER;{@4...{@4if^I in A'RANGE and then A(I) = 0.0~then{@7-----;{@7-----;  (block of code){@7-----;{@4end if;{{then we know the program won't try to evaluate^A(I)~when I is outside the range{1 to 10.{}b[ 304B302]Which one of these is^illegal`?{{{@*1.@$subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@0type GROUP is array(DAY_SUBTYPE) of FLOAT;{@0GR : GROUP;{@0...{@0GR(3) := 0.0;{{{@*2.@$type LIST is array(1 .. 10) of INTEGER;{@0type PAGE is array(1 .. 20) of LIST;{@0PG : PAGE;{@0...{@0PG(5)(10) := 0;{{{@*3.@$type ROW is array (INTEGER range <>) of INTEGER;{@0R1 : ROW;{@0...{@0R1(1) := 0;{}Please press 1, 2, or 3, or B to go back.[330513062307B303]@)^3.@$type ROW is array (INTEGER range <>) of INTEGER;`{@/^R1 : ROW;`{@/^...`{@/^R1(1) := 0;`{{%You're right!~ The above is illegal because the range of the subscript must be{specified, either in the first line,^(INTEGER range 1 .. 10)`, or in the{second,^R1 : ROW(1 .. 10);`, but not both.  This is the^unconstrained array`{error mentioned earlier.{}q[ 308B304Q304]@*1.@$subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@0type GROUP is array(DAY_SUBTYPE) of FLOAT;{@0GR : GROUP;{@0...{@0GR(3) := 0.0;{{No, the above is legal.  GP is an array of 31 elements.  The subscript ranges{from 1 to 31, and each element has type FLOAT.  Therefore, GP(3) has type{FLOAT, and the assignment is legal.{}q[ 308B304Q304]@*2.@$type LIST is array(1 .. 10) of INTEGER;{@0type PAGE is array(1 .. 20) of LIST;{@0PG : PAGE;{@0...{@0PG(5)(10) := 0;{{No, the above is legal.  The elements of an array can be of any type, including{other arrays.  Here PG has type PAGE, which is an array of LIST.  Therefore{PG(5) has type LIST (which is an array of INTEGER), and PG(5)(10) has type{INTEGER.  Thus the assignment is legal.  The notation PG(5)(10) may seem{strange, but it's correct Ada when we have an array of arrays.{}q[ 308B304Q304]@DSTRINGS{{There's one very important array type declaration built into the Ada language.{As with types BOOLEAN and CHARACTER, and subtypes POSITIVE and NATURAL, this{definition comes with Ada and shouldn't be repeated in our programs:{{@,^type STRING is array(POSITIVE range <>) of CHARACTER;`{{Thus we can declare, for example,^S : STRING(1 .. 5);`.  We can't simply write{%S : STRING;~or^S : STRING := "Hello";~because we can't declare unconstrained{array objects.  (We can declare^S : constant STRING := "Hello";`).  Note that{STRING isn't a special type in Ada, it's just an array of CHARACTERs.{Everything we learned about arrays applies to STRINGs.  For example, we can{assign to S using the same syntax that we use when assigning to an array of any{other type.  If we write^S : STRING(1 .. 5);~we can write:{{@7^S := ('H', 'e', 'l', 'l', 'o');`{{However, this notation is clumsy, so Ada allows us to abbreviate an array of{CHARACTER constants using the double quote.  Thus^S := "Hello";~is equivalent{to the statement above.  If a quotation mark appears inside the string, it must{be doubled.  Thus^TEXT_IO.PUT_LINE("a ""big"" man");~will display^a "big" man`.{}b[ 309B304]It may seem disappointing that Ada STRINGs have fixed length, and that we can't{declare a variable^S : STRING;`.  Later we'll learn how to define our own type{TEXT to get around this restriction and simulate variable-length STRINGs.{{When arrays are assigned, the^lengths~must be the same on both sides of the^:=`,{and the^types~must be the same, but the^subscripts~needn't be the same.{For example, if we have{{@/^type VECTOR is array(INTEGER range <>) of FLOAT;`{@/^V1 : VECTOR(1 .. 5);`{@/^V2 : VECTOR(2 .. 6) := (others => 0.0);`{{@/^S1 : STRING(1 .. 5);`{@/^S2 : STRING(2 .. 6) := (others => ' ');`{{then we can write^V1 := V2;~and^S1 := S2;~even though the subscripts are{different, because the array lengths are the same and the element types are the{same.  But we'll get a CONSTRAINT_ERROR if we write^S1 := "Hello there";~or{%S1 := "Hi";~or^V1 := (1.0, 2.0, 3.0);`, because these arrays have wrong lengths.{Ada won't automatically truncate STRINGs or pad with blanks.  Of course, it{would be easy to write our own procedure to assign STRINGs of different{lengths, padding or truncating as necessary.{}b[ 310B308]A^slice~of an array is a portion of an array, and is indicated with a^range~in{the subscript.  A slice is itself an array.  Some languages use the term{"substring" to refer to a slice of a STRING, but in Ada we can take a slice of{%any~kind of array, not just an array of CHARACTERs.  So instead of "substring,"{Ada uses the more general term "slice."  For example, if we have{{@&^A : array(1 .. 10) of INTEGER := (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);`{{then^A(1 .. 3)~is the array^(1, 2, 3)~and^A(6 .. 9)~is the array^(6, 7, 8, 9)`.{Similarly, if we have^S : STRING(1 .. 11) := "Hello there";~then^S(8 .. 11)~is{%"here"~and^S(4 .. 5)~is^"lo"`.  We can also write^S(1 .. 10) := S(2 .. 11);~and{%A(1 .. 3) := A(4 .. 6);~since the lengths are the same on both sides.{{If the value preceding^..~is greater than the value following it, we have a{%null range`.  A slice with a null range has a length of zero, and is called a{%null slice`.  In the case of a null slice, the subscript is^not~checked for{CONSTRAINT_ERROR.  Thus, even if N is 0 we could write^S(1 .. N);~which would{produce the null string^""`.  This is legal, even though Ada defines{"type STRING is array(%POSITIVE~range <>) of CHARACTER;".  Assigning a null{slice to a null slice does no harm and generates no error; it does nothing.{Also, if^S~is a null array, then^S'LENGTH~is 0, and^S'FIRST~and^S'LAST~don't{exist.  Using^FIRST~or^LAST~with a null array will raise a CONSTRAINT_ERROR.{}b[ 311B309]Beginners sometimes confuse a^CHARACTER~with a^STRING of length 1`.  If we{write{{@=^S : STRING(1 .. 10);`{@=^I : INTEGER := 5;`{{then^S(I)~is a CHARACTER and^S(I .. I)~is a STRING of length 1.  Also,^'X'~is a{CHARACTER while^"X"~is a STRING of length 1.  Thus we could write{{@>^S(I) := 'X';`{@>^S(I .. I) := "X";`{{but we'd be mixing types if we were to write^S(I) := "X";~or^S(I .. I) := 'X';`.{{Fortunately, TEXT_IO has a PUT for type CHARACTER as well as a PUT for type{STRING.  (It also has a GET for each of these types.)  Thus we can write either{%PUT(S(I .. I));~or^PUT(S(I));`.  However, PUT_LINE and GET_LINE exist only for{STRINGs, not for CHARACTERs.{}b[ 312B310]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{Which^one~of the above is legal?{}Please press 1, 2, 3, 4, 5, 6, or 7, or B to go back.[4313131423153316531763187319B311]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@#^4.  HELLO  : STRING(2 .. 6) := "Hello";`{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{%You're right!~ Number 4 creates HELLO, a STRING of length 5, and initializes it{to "Hello", a STRING of the same length.  The subscript of HELLO need not start{at 1, so long as the length is 5.{{Number 1 attempts to create an unconstrained array.  Number 2 has a zero{subscript, while Ada defines type STRING for POSITIVE subscripts.  Number 3{should have^'`*%'~instead of^"`*%"`.  Number 5 tries to set each of the first three{elements, which are CHARACTERs, to a STRING.  Number 6 tries to store a STRING{of length 1 into a STRING of length 3, and number 7 should have^"`Hello%"`{instead of^'`Hello%'`.{}q[ 320B312Q312]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{No, number 1 is illegal because it tries to create an unconstrained array.  The{fact that^"Hello there"~has a definite length doesn't make the statement legal.{We must constrain the STRING to a length of 11 by writing, for example,{%HELLO  : STRING(1 .. 11) := "Hello there";`.  However, it^is~legal to write{{@3HELLO :^constant~STRING := "Hello there";{}q[ 320B312Q312]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{No, number 2 is illegal because of the zero subscript.  Ada defines "type{STRING is array(%POSITIVE~range <>) of CHARACTER;".  Therefore, the subscripts{must be 1 or greater.{}q[ 320B312Q312]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{No, number 3 is illegal because^"`*%"~should be^'`*%'`.  As it stands, it tries to{assign a STRING of length 1 to each of the elements, which are CHARACTERs.{}q[ 320B312Q312]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{No, number 5 is illegal because it tries to initialize each of the first three{elements, which are CHARACTERs, to a STRING of length 3.  We could, however,{have written simply^HELLO : STRING(1 .. 5);`, and then written the following in{the executable region:{{@;^HELLO(1 .. 3) := "Hel";`{@;^HELLO(4) := 'l';`{@;^HELLO(5) := 'o';`{}q[ 320B312Q312]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{No, number 6 is illegal because it tries to assign a STRING of length 1 to a{STRING of length 3.{}q[ 320B312Q312]@$1.  HELLO  : STRING := "Hello there";{@$2.  DIGIT  : STRING(0 .. 9) := "0123456789";{@$3.  LINE@#: STRING(1 .. 80) := (others => "*");{@$4.  HELLO  : STRING(2 .. 6) := "Hello";{@$5.  HELLO  : STRING(1 .. 5) := (1 .. 3 => "Hel",  4 => 'l',  5 => 'o');{@$6.  PROMPT : STRING(1 .. 3) := ">";{@$7.  HELLO  : STRING(1 .. 5) := 'Hello';{{{No, number 7 is illegal because it should say^"`Hello%"~instead of^'`Hello%'`.  Ada{"tic" marks (%'`) always enclose a single CHARACTER, while double quotes (%"`){always enclose an array of CHARACTERs.{}q[ 320B312Q312]@@ARRAY OPERATORS{{The operator^&~concatenates any two arrays of the same type, including two{STRINGs.  It can also concatenate a single element with an array of that{element type, or two single elements into an array of length two.  For example,{every use of^&~below is legal:{{@+C, D : CHARACTER := '*';{@+S2@#: STRING(1 .. 2);{@+S3@#: STRING(1 .. 3) := (others => ' ');{@+S5@#: STRING(1 .. 5);{{@+type VECTOR is array(INTEGER range <>) of FLOAT;{@+F, G : FLOAT := 1.2;{@+V2@#: VECTOR(1 .. 2);{@+V3@#: VECTOR(1 .. 3) := (others => 0.0);{@+V5@#: VECTOR(1 .. 5);{@+...{@*^S2 := C & D;  S5 := S2 & S3;  S3 := C & S2;  S3 := S2 & C;`{@*^V2 := F & G;  V5 := V2 & V3;  V3 := F & V2;  V3 := V2 & F;`{}b[ 321B312]The operators^and`,^or`,^xor`, and^not`, defined for BOOLEANs, are also defined for{one-dimensional arrays of BOOLEAN.  They operate element by element on the{arrays.  Thus, we can simulate^sets~in Ada.  For example, if we write{{@#^type SET_OF_CHARS is array(CHARACTER) of BOOLEAN;`{@#^S1 : SET_OF_CHARS := SET_OF_CHARS'('*' | '#' => TRUE, others => FALSE);`{@#^S2 : SET_OF_CHARS := SET_OF_CHARS'('*' | '?' => TRUE, others => FALSE);`{{then^S1 or S2~is^SET_OF_CHARS'('*' | '#' | '?' => TRUE, others => FALSE)`,{and^S1 and S2~is^SET_OF_CHARS'('*' => TRUE, others => FALSE)`.{{The operators^=~and^/=~can compare two records or two arrays of the same type.{Records are equal if all of their corresponding fields are equal, arrays, if{all of their corresponding elements are equal.  Arrays of different lengths{are always unequal.  The four remaining relational operators can compare two{arrays of the same type.  They're compared element by element until a{difference is found.  For example, if we have{{@7^S : STRING(1 .. 6) := "to all";`{@7^T : STRING(1 .. 7) := "to Bill";`{{then^S > T~because 'a' > 'B' in Ada's definition of type CHARACTER.{}b[ 322B320]@3OUTSIDE ASSIGNMENT 3 - EXERCISE IN RECORDS{{Your third Outside Assignment is to write a function specified by{{@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{@%subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@%type DATE is{@(record{@+DAY@#: DAY_SUBTYPE;{@+MONTH : MONTH_TYPE;{@+YEAR  : INTEGER;{@(end record;{@$^function TOMORROW(TODAY : in DATE) return DATE;`{{Given any date, TOMORROW should return the following date.  Your function will{be tested only with legal dates.  As with Outside Assignment 2, a test driver{is already written; it's in^NEXTDATE.ADA`.  A listing is on page 13 of your{printed course notes, but you needn't understand the test driver.  If your{function fails any test, you'll see the test case, the answer from your{function, and the right answer.  Otherwise, you'll see "Congratulations, you{completed the assignment!"{}b[ 323B321]The definitions of MONTH_TYPE, DAY_SUBTYPE, and DATE are in the test driver;{you shouldn't define them inside your function.  A dummy solution is in{%TOMORROW.DUM`; it looks like this:{{@/-- Dummy solution to Outside Assignment 3{@.^separate (NEXTDATE)`{@.^function TOMORROW(TODAY : in DATE) return DATE is`{@.^begin`{@2return TODAY;{@.^end TOMORROW;`{{Again, you'll probably want to remove or change the comment line, and you{shouldn't change the lines^highlighted~above.  You may, but don't have to,{include^ANSWER : DATE;~in the declarative region and make^return ANSWER;~the{last statement before^end TOMORROW;`.{{Normally, years divisible by 4 are leap years.  But if a year is divisible by{100, it must also be divisible by 400 to be a leap year.  Thus, 2000 is a leap{year, but 1900 and 2100 are not.  Note that^TODAY.YEAR~is divisible by 4 if and{only if^TODAY.YEAR mod 4 = 0`.  You may assume that^TODAY.YEAR~will always be{between 1583 and 3999, because outside this range the calendar gets more{complicated.{}b[ 324B322]The steps to follow for Outside Assignment 3 are very similar to those of{Outside Assignment 2.  They're in your printed course notes on page 14:{{1.  Compile the test driver NEXTDATE.ADA.  Also, make a copy of the dummy{@$solution by typing^COPY TOMORROW.DUM TOMORROW.ADA`.  You need do this step{@$only once.{{2.  Edit TOMORROW.ADA to become your real solution.  You may skip this step the{@$first time through, to see error messages from the test driver.{{3.  Compile TOMORROW.ADA.  If the compiler finds errors, go back to step 2.{{4.  Link with the name of the main program NEXTDATE.  Then execute.  If the{@$test driver displays error messages, go back to step 2.{{5.  When the message "Congratulations, you completed the assignment!" is{@$displayed, you'll have a chance to compare your solution with ours.{}b[ 325B323]There are many ways to solve this problem.  In our solution we declared an{array of DAY_SUBTYPE with subscripts of type MONTH_TYPE.  Some students use a{%case~construct on TODAY.MONTH; some use an^if~block with^elsif`s.{{This assignment should be a simple exercise in records.  Our solution fits on{one screen.  If your solution starts to get long and difficult, you should{think the problem through again.  Don't try to save the computer a few{microseconds; computers are supposed to save people time.  Instead, minimize{the^complexity~of the program to save yourself programming effort!{{Remember that an entire record can be assigned in one statement.  Also, try to{calculate the number of days in the month and^then~test for end of month and{end of year in only one place.  This is better than having several blocks of{code testing for end of month and end of year in three or four different places{in your program.  One last hint: remember that MONTH_TYPE'SUCC(TODAY.MONTH){will raise a CONSTRAINT_ERROR if TODAY.MONTH is DEC.{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 3.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 326B324]@-^Congratulations on Completing Outside Assignment 3!`{{-- Our solution to Outside Assignment 3 (in TOMORROW.ANS):{separate (NEXTDATE){function TOMORROW(TODAY : in DATE) return DATE is{@#LENGTH : array(MONTH_TYPE) of DAY_SUBTYPE :={@>(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);{@#ANSWER : DATE;{begin{@#if TODAY.YEAR mod 4 = 0 and{@7(TODAY.YEAR mod 100 /= 0 or TODAY.YEAR mod 400 = 0) then{@&LENGTH(FEB) := 29;{@#end if;{@#if TODAY.DAY /= LENGTH(TODAY.MONTH) then@0-- Not end of month.{@&ANSWER := (TODAY.DAY + 1, TODAY.MONTH, TODAY.YEAR);{@#elsif TODAY.MONTH /= DEC then@*-- End of month, but not end of year.{@&ANSWER := (1, MONTH_TYPE'SUCC(TODAY.MONTH), TODAY.YEAR);{@#else@Y-- End of year.{@&ANSWER := (1, JAN, TODAY.YEAR + 1);{@#end if;{@#return ANSWER;{end TOMORROW;{}b[ 327B325]In our solution, the first^if~statement checks for leap year.  No^else~is{needed because the locally declared array^LENGTH~is re-initialized every time{the function is called.  After this^if~statement, the number of days in the{month is in^LENGTH(TODAY.MONTH)`, and it's easy to test for end of month and end{of year - in only one place in the program.{{We could have written^MONTH_TYPE'LAST~instead of^DEC`, and^MONTH_TYPE'FIRST`{instead of^JAN`.  We could even have used^DAY_SUBTYPE'FIRST`.  But the author{reasoned that if our calendar ever changes, the entire program will probably{have to be rewritten anyway!  The program seems a little easier to read when we{use the names^DEC~and^JAN~and the number^1~directly.{{Your solution might be entirely different from ours.  If the test driver said{"Congratulations, you completed the assignment!" you may consider your solution{correct.  Let's go on to discuss recursion.{}b[ 328B326]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@)^>  RECURSION AND ASSIGNMENT 4`{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 329B327]@CRECURSION{{Ada procedures and functions may call themselves, directly or indirectly.  This{process is called^recursion`.  While recursion often uses a little extra memory{and execution time, for certain types of problems it pays large dividends in{program simplicity.  That's a very worthwhile exchange!{{For example, let's write a function to compute the factorial of a positive{integer.  The factorial of an integer is the product of all the integers from{that number down to one.  Thus, FACTORIAL(5) = 5 * 4 * 3 * 2 * 1 = 120.{Although we could easily write this function with a^for~loop, we'll use{recursion instead.  Note that if N = 1, then FACTORIAL(N) = 1; otherwise,{FACTORIAL(N) = N * FACTORIAL(N - 1).{{@-function FACTORIAL(N : in POSITIVE) return POSITIVE is{@0ANSWER : POSITIVE := 1;{@-begin{@0if N > 1 then{@3ANSWER := N * FACTORIAL(N - 1);{@0end if;{@0return ANSWER;{@-end FACTORIAL;{}b[ 330B328]@-function FACTORIAL(N : in POSITIVE) return POSITIVE is{@0ANSWER : POSITIVE := 1;{@-begin{@0if N > 1 then{@2^ANSWER := N * FACTORIAL(N - 1);`{@0end if;{@0return ANSWER;{@-end FACTORIAL;{{The highlighted line shows where this function calls itself.  Recursive{subprograms always call themselves^conditionally`; otherwise the program would{run out of memory, no matter how large the machine.  Here the recursive call is{inside an^if~block.{{Note that ANSWER is initialized to 1.  If the function is called with N = 1,{the^if~statement is FALSE, ANSWER isn't modified, and^1~is returned as the{value of the function.  If the function is called with N = 2, the^if~statement{is TRUE, and the highlighted line is executed.  The machine starts to compute{the expression as 2 * ..., and then FACTORIAL is called with N = 1.  It's as if{the machine made another copy of the code for FACTORIAL and called that.{Actually there's only one copy of the code, but the machine maintains multiple{%pointers~to it.{}b[ 331B329]@-function FACTORIAL(N : in POSITIVE) return POSITIVE is{@0ANSWER : POSITIVE := 1;{@-begin{@0if N > 1 then{@2^ANSWER := N * FACTORIAL(N - 1);`{@0end if;{@0return ANSWER;{@-end FACTORIAL;{{When the recursive call is made, the system allocates additional memory for new{versions of any local variables like ANSWER.  Also, the parameters like N are{separate for each recursive call.{{Suppose the main program calls FACTORIAL with N = 2.  Then, in computing the{expression, FACTORIAL calls itself with N = 1.  In this second call, a new{local variable ANSWER is created, separate from the one in the first call.{Also, parameter N is 1 in the second call, but 2 in the first call.  In the{second call, the^if~statement is FALSE, and 1 is returned.  In the first call,{the calculation of the expression is completed, using the value 1 returned by{the second call.  Thus, ANSWER becomes 2 * 1 = 2, and the first call returns{the answer 2 to the main program.{}b[ 332B330]@-function FACTORIAL(N : in POSITIVE) return POSITIVE is{@0ANSWER : POSITIVE := 1;{@-begin{@0if N > 1 then{@2^ANSWER := N * FACTORIAL(N - 1);`{@0end if;{@0return ANSWER;{@-end FACTORIAL;{{If the main program calls FACTORIAL with N = 3, the function starts to compute{the expression as ANSWER := 3 * ..., and calls FACTORIAL with N = 2.  In this{second call, the function starts to compute ANSWER := 2 * ..., and calls{FACTORIAL with N = 1.  In this third call, the^if~statement is FALSE, and the{answer 1 is returned to the second call.  The second call finishes the{computation of the expression ANSWER := 2 * 1, and returns the answer 2 to the{first call.  Finally, the first call finishes computing the expression with{ANSWER := 3 * 2, and returns the answer 6 to the main program.{{This simple function wouldn't have been complicated even without recursion.  In{a moment we'll discuss the Tower of Hanoi problem.  The recursive solution is{very simple, but a solution without recursion would be very complicated indeed.{}b[ 333B331]In this question, function A calls B, and B conditionally calls A.  The{specification of function B is given early so that A can call it.{{@1function B (I : in INTEGER) return INTEGER;{{@1function A (I : in INTEGER) return INTEGER is{@1begin{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in INTEGER) return INTEGER is{@4ANS : INTEGER := 0;{@1begin{@4if I > 0 then{@7ANS := A(I);{@4end if;{@4return ANS;{@1end B;{{If the main program calls function A with a parameter equal to 2, what value{will A return:  0, 1, 2, or 3?  You may need pencil and paper to figure this{one out.{}Please press 0, 1, 2, or 3, or B to go back.[2334033513353335B332]@1function B (I : in INTEGER) return INTEGER;{{@1function A (I : in INTEGER) return INTEGER is{@1begin{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in INTEGER) return INTEGER is{@4ANS : INTEGER := 0;{@1begin{@4if I > 0 then{@7ANS := A(I);{@4end if;{@4return ANS;{@1end B;{{%You're right!~ When the main program calls A(2), A starts to evaluate{B(1) + 1.  The^if~statement in B is TRUE, so B simply calls A(1).  The call{A(1) starts to evaluate B(0) + 1.  The^if~statement in this call to B is FALSE,{so B(0) simply returns 0, and the call A(1) returns 0 + 1 = 1.  The call B(1){returns the same answer, so the call A(2) returns 1 + 1 = 2.{}q[ 336B333Q333]@1function B (I : in INTEGER) return INTEGER;{{@1function A (I : in INTEGER) return INTEGER is{@1begin{@4return B(I - 1) + 1;{@1end A;{{@1function B (I : in INTEGER) return INTEGER is{@4ANS : INTEGER := 0;{@1begin{@4if I > 0 then{@7ANS := A(I);{@4end if;{@4return ANS;{@1end B;{{No, when the main program calls A(2), A starts to evaluate B(1) + 1.  The^if`{statement in B is TRUE, so B simply calls A(1).  The call A(1) starts to{evaluate B(0) + 1.  The^if~statement in this call to B is FALSE, so B(0) simply{returns 0, and the call A(1) returns 0 + 1 = 1.  The call B(1) returns the same{answer, so the call A(2) returns 1 + 1 = 2.{}q[ 336B333Q333]@;THE TOWER OF HANOI PROBLEM{{The "Tower of Hanoi" is a solitaire puzzle that was named when Hanoi was the{capital of a free country: French Indochina.  There are three pegs labeled A,{B, and C; one of them has a tower of N doughnut-shaped disks of decreasing{size, like this:{{@/|@7|@7|{@/|@7|@7|{@.=|=@6|@7|{@-==|==@5|@7|{@,===|===@4|@7|{@+====|====@3|@7|{@*=====|=====@2|@7|{@'-----------------@'-----------------@'-----------------{@/A@7B@7C{{The object is to move the entire tower from one peg to another, say, from A to{B.  Only one disk may be moved at a time, and a larger disk may never be placed{on top of a smaller one.  The shortest solution to the puzzle with N disks{requires 2**N - 1 moves.{}b[ 337B333]For example, we can move five disks from A to B with the following 31 moves:{(Read them from left to right, not in columns.){{A to B,  A to C,  B to C,  A to B,  C to A,  C to B,  A to B,  A to C,  B to C,{B to A,  C to A,  B to C,  A to B,  A to C,  B to C,  A to B,  C to A,  C to B,{A to B,  C to A,  B to C,  B to A,  C to A,  C to B,  A to B,  A to C,  B to C,{A to B,  C to A,  C to B,  A to B.{{@/|@7|@7|{@/|@7|@7|{@/|@7|@7|{@/|@7|@7|{@.=|=@6|@7|{@+====|====@3|@7|{@*=====|=====@/===|===@2==|=={@'-----------------@'-----------------@'-----------------{@/A@7B@7C{@4(The Puzzle After the First Five Moves){{Writing a program to display this series of moves would be very complicated{without recursion.  Let's develop a recursive solution; we'll see that the{resulting Ada program is surprisingly simple!{}b[ 338B336]When we developed a recursive solution for the FACTORIAL function:{{@1if N = 1,  FACTORIAL(N) = 1{@1otherwise, FACTORIAL(N) = N * FACTORIAL(N - 1){{we expressed FACTORIAL(N) in terms of FACTORIAL(N - 1), and gave the trivial{solution for N = 1.  The Ada program was easily written from the above.{{For the Tower of Hanoi problem, let's develop a solution for N disks in terms{of a solution for N - 1 disks.  Suppose we want to move five disks from A to B,{using C as a spare peg.  We first move^four~disks from A to^C`, then move one{disk from A to B, and finally move four disks from C to B.  In general, to move{N disks from a source peg to a destination peg, we first move N - 1 disks from{the source to the spare, then move one disk from the source to the destination,{and finally move N - 1 disks from the spare to the destination.{{To move the^one~disk from the source to the destination, our program will{simply display the move.  To move N - 1 disks, the program will call itself.{The solution for zero disks is trivial indeed: the program will do nothing!{{The following program is extremely simple: three executable statements inside{an^if~block.  Yet it can display a very complicated series of moves!{}b[ 339B337]@&^with TEXT_IO; use TEXT_IO;`{@&^procedure HANOI(N : in NATURAL; FROM, TO, SPARE : in CHARACTER) is`{@&^begin`{@)^if N > 0 then`{@,^HANOI(N - 1, FROM, SPARE, TO);`{@,^PUT_LINE(FROM & " to " & TO);`{@,^HANOI(N - 1, SPARE, TO, FROM);`{@)^end if;`{@&^end HANOI;`{{To move five disks from A to B, using C as a spare, we would call{%HANOI(5, 'A', 'B', 'C');~and the program would display the 31 moves.{{Note that when HANOI is called with N = 0, it does nothing.  When called with{N = 1, the^if~statement is true, and the three lines within the^if~block are{executed.  But the first and third lines do nothing, because they call HANOI{with N = 0.  The second line displays, for example,^A to B`.{{When called with a larger value of N, the first line within the^if~block moves{N - 1 disks from the source to the spare peg.  The second line displays the{move of one disk from the source to the destination, and the third line moves{N - 1 disks from the spare peg to the destination.{}b[ 340B338]Most implementations of Ada won't allow HANOI to be a main program, because it{has parameters.  A short main program to call HANOI is shown here.  A slightly{longer program could get N and the names of the three pegs from the user.  In{this example, procedure DEMO^with`s a previously compiled~procedure~rather than{a~package`.{{@9^with HANOI;`{@9^procedure DEMO is`{@9^begin`{@<^HANOI(5, 'A', 'B', 'C');`{@9^end DEMO;`{{In summary, our first example of recursion, FACTORIAL, was very simple.{However, that program would have been simple even without recursion.  Our{second example, HANOI, also was very simple, but the program would have been{quite complicated without recursion.{{Our fourth Outside Assignment will be to write a Fibonacci function FIB, using{recursion.  As with FACTORIAL, this function would be easy to write even{without recursion.  However, as an exercise we'll write it using recursion.{}b[ 341B339]@2OUTSIDE ASSIGNMENT 4 - EXERCISE IN RECURSION{{Your fourth Outside Assignment is to write, using recursion, a function{specified by{{@0^function FIB(N : in POSITIVE) return POSITIVE;`{{Fibonacci was a mathematician in the Middle Ages.  The so-called^Fibonacci{Series~is a series of integers.  Each number in the series is the sum of the{two previous numbers.  The first two Fibonacci numbers are 1.{{@%N:@$1  2  3  4  5  6@#7@#8@#9  10  11@#12@#13@#14@#15@#16 ...{@#FIB(N): 1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987 ...{{Note that if N = 1 or N = 2, then FIB(N) = 1; otherwise,{FIB(N) = FIB(N - 1) + FIB(N - 2).  Writing this function in Ada will be an easy{and short assignment.  A test driver is provided in^FIBTEST.ADA`; a listing is{on page 15 of your printed course notes.  As before, if all tests are passed,{it displays "Congratulations, you completed the assignment!"  If there's an{error, it displays the test case, the answer from your function, and the right{answer.{}b[ 342B340]A dummy solution is in^FIB.DUM`.  As before, you shouldn't change the lines{%highlighted~here:{{@0-- Dummy solution to Outside Assignment 4{@/^separate (FIBTEST)`{@/^function FIB(N : in POSITIVE) return POSITIVE is`{@/^begin`{@3return 4;{@/^end FIB;`{{{The steps to follow for Outside Assignment 4 are similar to those of the last{two Outside Assignments.  They're in your printed course notes on page 16:{}b[ 343B341]1.  Compile the test driver FIBTEST.ADA.  Also, make a copy of the dummy{@$solution by typing^COPY FIB.DUM FIB.ADA`.  You need do this step only once.{{2.  Edit FIB.ADA to become your real solution.  You may skip this step the{@$first time through, to see error messages from the test driver.{{3.  Compile FIB.ADA.  If the compiler finds errors, go back to step 2.{{4.  Link with the name of the main program FIBTEST.  Then execute.  If the test{@$driver displays error messages, go back to step 2.{{5.  When the message "Congratulations, you completed the assignment!" is{@$displayed, you'll have a chance to compare your solution with ours.{{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 4.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 344B342]@-^Congratulations on Completing Outside Assignment 4!`{{@--- Our solution to Outside Assignment 4 (in FIB.ANS):{@-separate (FIBTEST){@-function FIB(N : in POSITIVE) return POSITIVE is{@0ANSWER : POSITIVE := 1;{@-begin{@0if N > 2 then{@3ANSWER := FIB(N - 1) + FIB(N - 2);{@0end if;{@0return ANSWER;{@-end FIB;{{Your solution is probably quite similar to ours.  Perhaps you used^else~and{didn't initialize ANSWER in the declarative region.  Perhaps you had some other{minor variation.  Our solution is probably no "better" than yours, if the test{driver said, "Congratulations, you completed the assignment!"{{Was this assignment^too~easy?  We promise that Outside Assignment 5 will be{much more challenging!  But first we need to discuss procedures and functions{in more detail, as well as packages and information hiding, access types, and{exceptions.{}b[ 345B343]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@,^>  SUBPROGRAMS AND PACKAGES`{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 346B344]@<PROCEDURES AND FUNCTIONS{{When we compiled procedures HELLO and ADD into the library, we made it possible{for other units to^with~them and call them.  (We don't^use~procedures and{functions, because dot notation doesn't apply to them.)  We can also compile{just a^specification`, supplying the body later.  For example, we could compile{{@(^function UPPER_CASE(S : in STRING) return STRING;`{{and then compile the calling program.  When we later write the body, it must{agree with the specification:{{@(^function UPPER_CASE(S : in STRING) return STRING is`{@,ANSWER : STRING(S'RANGE) := S;{@)begin{@,for I in S'RANGE loop{@/if S(I) in 'a' .. 'z' then{@2ANSWER(I) := CHARACTER'VAL(CHARACTER'POS(S(I)) - 32);{@/end if;{@,end loop;{@,return ANSWER;{@)end UPPER_CASE;{}b[ 347B345]Functions and procedures may also be declared locally, in which case they must{follow any simple declarations like^I : INTEGER;~or^S : STRING(1 .. 5);`.{{@'with TEXT_IO; use TEXT_IO;{@'procedure GREETING is{@*S : STRING(1 .. 5) := "Hello";{@)^function UPPER_CASE(S : in STRING) return STRING is`{@,^ANSWER : STRING(S'RANGE) := S;`{@)^begin`{@,^for I in S'RANGE loop`{@/^if S(I) in 'a' .. 'z' then`{@2^ANSWER(I) := CHARACTER'VAL(CHARACTER'POS(S(I)) - 32);`{@/^end if;`{@,^end loop;`{@+^return ANSWER;`{@)^end UPPER_CASE;`{@'begin{@*PUT_LINE(UPPER_CASE(S));{@'end GREETING;{{As we've seen, we can declare local functions and procedures to be^separate`.{These subprograms can in turn declare^separate~subprograms, to any depth:{}b[ 348B346]@2procedure MAIN is{@5function A return FLOAT is separate;{@2begin{@5...{@2end MAIN;{{@1^separate (MAIN)`{@2function A return FLOAT is{@5procedure B is separate;{@2begin{@5...{@2end A;{{@1^separate (MAIN.A)`{@2procedure B is{@5procedure C(I : in INTEGER) is separate;{@2begin{@5...{@2end B;{{@1^separate (MAIN.A.B)`{@2procedure C(I : in INTEGER) is ... (etc.){}b[ 349B347]However,^is separate~may be used only at the outermost level.  The example{below is legal as it stands, but we may not make procedure B separate unless we{also make function A separate, thus bringing function A to the outermost level:{{@9procedure MAIN is{@<F : FLOAT;{@<function A return FLOAT is{@?ANSWER : FLOAT;{@?procedure B is{@?begin{@B...{@?end B;{@<begin{@?...{@?return ANSWER;{@<end A;{@9begin{@<...{@9end MAIN;{{A program that begins^separate (`...%)~must be compiled after the program that{says^is separate`, because a separate subprogram depends on its "parent."{}b[ 350B348]A procedure or function specification gives the name, mode, and type of each{parameter.  A function specification also gives the type of the result.  The{mode can be^in`,^out`, or^in out`.  The subprogram may read from, but not write{to,^in~parameters, and it may write to, but not read from,^out~parameters.  If{the mode is omitted, it's assumed to be^in`.  Thus, these two lines have the{same effect:{{@'^procedure HANOI(N : in NATURAL; FROM, TO, SPARE : in CHARACTER);`{@'^procedure HANOI(N : NATURAL;@$FROM, TO, SPARE : CHARACTER);`{{The parameters of a^function~must always be of mode^in`, never^out~or^in out`.{{Note that when several parameters have the same mode and type, they can be{placed in one list, separated by commas.  The lists themselves are separated by{semicolons.  The two specifications above are equivalent to:{{%procedure HANOI(N : NATURAL; FROM: CHARACTER; TO: CHARACTER; SPARE: CHARACTER);`{{In any event, the parameters in a^call~to a procedure or function are always{separated by^commas`:{{@;^HANOI(5, 'A', 'B', 'C');`{}b[ 351B349]@#1.  procedure P(A; B; C : in INTEGER);{{@#2.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#3.  function  F(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#4.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT);{{{Which one of the above is^legal`?{}Please press 1, 2, 3, or 4, or B to go back.[4352135323543355B350]@#1.  procedure P(A; B; C : in INTEGER);{{@#2.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#3.  function  F(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{  ^4.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT);`{{%You're right!~ In a subprogram specification, the items of a list are separated{by commas, and the lists are separated by semicolons.  In a list, the mode may{be omitted; it's assumed to be^in`.{{In number 1, the items should be separated by commas.  Number 2 has a^return`{clause in a^procedure~specification, and number 3 has a mode other than^in~in a{%function~specification.{}q[ 356B351Q351]@#1.  procedure P(A; B; C : in INTEGER);{{@#2.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#3.  function  F(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#4.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT);{{No, in number 1 the items should be separated by commas, not semicolons.  In a{subprogram specification, the items in a list are separated by commas, and the{lists are separated by semicolons.  Here a "list" means a collection of{parameters sharing the same mode and type (%in INTEGER`).{}q[ 356B351Q351]@#1.  procedure P(A; B; C : in INTEGER);{{@#2.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#3.  function  F(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#4.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT);{{No, number 2 is illegal because a^return~clause applies only to a function{specification, not a procedure specification.{}q[ 356B351Q351]@#1.  procedure P(A; B; C : in INTEGER);{{@#2.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#3.  function  F(A, B, C : INTEGER; D, E : in out FLOAT) return CHARACTER;{{@#4.  procedure P(A, B, C : INTEGER; D, E : in out FLOAT);{{No, number 3 is illegal because all parameters of a function must have mode^in`.{}q[ 356B351Q351]Recall that type conversion from FLOAT to INTEGER in Ada rounds to the nearest{integer.  (The Ada standard doesn't specify which way rounding occurs when the{fractional part is exactly 0.5.)  This function FLOOR computes the largest{integer less than or equal to a given FLOAT, always rounding toward negative{infinity:{{@1function FLOOR(X : in FLOAT) return INTEGER is{@4ANSWER : INTEGER := INTEGER(X);{@1begin{@4if FLOAT(ANSWER) > X then{@7ANSWER := ANSWER - 1;{@4end if;{@4return ANSWER;{@1end FLOOR;{}b[ 357B351]Similarly, this function TRUNCATE converts from FLOAT to INTEGER, always{truncating toward zero:{{@/function TRUNCATE(X : in FLOAT) return INTEGER is{@2ANSWER : INTEGER := INTEGER(X);{@/begin{@2if ANSWER > 0 and FLOAT(ANSWER) > X then{@5ANSWER := ANSWER - 1;{@2elsif ANSWER < 0 and FLOAT(ANSWER) < X then{@5ANSWER := ANSWER + 1;{@2end if;{@2return ANSWER;{@/end TRUNCATE;{}b[ 358B356]@?DEFAULT PARAMETERS{{The^in~parameters of a subprogram specification may be given default values.{Suppose, for example, that the package INTEGER_IO is instantiated for the type{INTEGER.  Here's a simplified version of the specification for the procedure{PUT (the actual specification can be found in section 14.3.10 of the LRM):{{@3^procedure PUT(ITEM  : in INTEGER;`{@A^WIDTH : in INTEGER := 6;`{@A^BASE  : in INTEGER := 10);`{{This means that, in calls to PUT, the WIDTH and BASE parameters are optional.{If WIDTH is omitted, it's assumed to be 6, and if BASE is omitted, it's assumed{to be 10.  If either of these parameters is given in the call, the default{value is overridden.  (The default value for WIDTH is shown here as 6.{Actually, it depends on the implementation of Ada.  Of course, the default{value for BASE is always 10.){{Default parameters let us make our Ada subprograms both^flexible~and^easy to`{%use`.  In other languages, we'd often have to choose between these two{qualities.  For example, suppose J is an integer.  Here are some calls to PUT:{}b[ 359B357]@4procedure PUT(ITEM  : in INTEGER;{@BWIDTH : in INTEGER := 11;{@BBASE  : in INTEGER := 10);{{@3^PUT(J);`{@3^PUT(J, WIDTH => 4);`{@3^PUT(J, BASE => 16);`{@3^PUT(J, BASE => 16, WIDTH => 4);`{{The first parameter in each call could have been given as^ITEM => J`, but{everyone remembers that the first parameter of PUT is the item, so named{notation seems unnecessary for this parameter.  However, WIDTH and BASE are{used less frequently.  We used named notation for these parameters so the{reader of our code wouldn't have to remember which parameter comes second and{which comes third.  Note that if we omit the second parameter and specify the{third, we^must~use named notation for the third parameter; we're not allowed to{write PUT(J, ,16); as in some languages.{{If we were writing PUT in another language, we'd have to choose either making{the user specify the width and the base in every call (giving flexibility), or{writing PUT with only one parameter (giving ease of use).  In Ada, default{parameters give us both flexibility and ease of use!{}b[ 360B358]TEXT_IO.NEW_LINE has one parameter, SPACING, defaulted to 1.  Thus, we can call{%NEW_LINE;~to get one CR-LF, or, for example,^NEW_LINE(3);~to get three.{{Default values may also be given in record definitions.  If we write{{@%type MONTH_TYPE is (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC);{@%subtype DAY_SUBTYPE is INTEGER range 1 .. 31;{@%type DATE is{@(record{@+DAY@#: DAY_SUBTYPE;{@+MONTH : MONTH_TYPE;{@+YEAR  : INTEGER^:= 1776`;{@(end record;{@%USA : DATE;{{then^USA.YEAR~is set to 1776 when the line declaring^USA~is elaborated.  Every{time an object of type DATE is declared, its YEAR field is set to 1776.{However, there's a difference between default values in records and default{parameters in subprograms.  We can't write USA := (4, JUL); all three fields of{the record must be specified.{}b[ 361B359]@4procedure PUT(ITEM  : in INTEGER;{@BWIDTH : in INTEGER := 11;{@BBASE  : in INTEGER := 10);{{Which one of these is^legal`?{{@:1.  PUT(ITEM => 23, 5, 10);{{@:2.  PUT(23, 5);{{@:3.  PUT(23; 5; 10);{}Please press 1, 2, or 3, or B to go back.[236213633364B360]@4procedure PUT(ITEM  : in INTEGER;{@BWIDTH : in INTEGER := 11;{@BBASE  : in INTEGER := 10);{{{@:1.  PUT(ITEM => 23, 5, 10);{{@9^2.  PUT(23, 5);`{{@:3.  PUT(23; 5; 10);{{{%You're right!~ The third parameter may be omitted because it has a default{value.  In number 1, positional notation follows named, which isn't allowed,{and in number 3, the separators should be commas.{}q[ 365B361Q361]@4procedure PUT(ITEM  : in INTEGER;{@BWIDTH : in INTEGER := 11;{@BBASE  : in INTEGER := 10);{{{@:1.  PUT(ITEM => 23, 5, 10);{{@:2.  PUT(23, 5);{{@:3.  PUT(23; 5; 10);{{{No, number 1 is illegal because positional notation may not follow named.{}q[ 365B361Q361]@4procedure PUT(ITEM  : in INTEGER;{@BWIDTH : in INTEGER := 11;{@BBASE  : in INTEGER := 10);{{{@:1.  PUT(ITEM => 23, 5, 10);{{@:2.  PUT(23, 5);{{@:3.  PUT(23; 5; 10);{{{No, number 3 is illegal because in a call, the parameters are always separated{with commas, not semicolons.{}q[ 365B361Q361]@DPACKAGES{{A^package~lets us group related declarations, procedures, and functions.  A{program can^with~the package and gain access to all of these.  However, as{we'll see, packages have many other advantages.  Usually library units are{packages rather than individual procedures and functions.{{By way of example, consider a very simple procedure and a very simple function:{{@)^procedure DOUBLE(NUMBER : in INTEGER; ANSWER : out INTEGER);`{@)^function TWICE(NUMBER : in INTEGER) return INTEGER;`{{We could compile these individually, or we could put them in a^package~and{compile that instead.  Here's the package^specification`:{{@'^package SIMPLE_MATH is`{@+procedure DOUBLE(NUMBER : in INTEGER; ANSWER : out INTEGER)%;`{@+function TWICE(NUMBER : in INTEGER) return INTEGER%;`{@'^end SIMPLE_MATH;`{{The package^body~must contain the bodies of all the procedures and functions{declared in the package specification:{}b[ 366B361]@&^package body SIMPLE_MATH is`{@*procedure DOUBLE(NUMBER : in INTEGER; ANSWER : out INTEGER)^is`{@*begin{@-ANSWER := NUMBER * 2;{@*end DOUBLE;{{@*function TWICE(NUMBER : in INTEGER) return INTEGER^is`{@*begin{@-return NUMBER * 2;{@*end TWICE;{@&^end SIMPLE_MATH;`{{The package body could optionally declare either or both subprograms to be{%separate`:{{ ^package body SIMPLE_MATH is`{@%procedure DOUBLE(NUMBER : in INTEGER; ANSWER : out INTEGER)^is separate;`{@%function TWICE(NUMBER : in INTEGER) return INTEGER^is separate;`{ ^end SIMPLE_MATH;`{{Here's an example of a calling program that^with`s the package and makes use of{the two subprograms declared in the package specification:{}b[ 367B365]@$^with SIMPLE_MATH; use SIMPLE_MATH;`{@%procedure PACKAGE_DEMO is{@(I, J : INTEGER := 10;{@%begin{@'^DOUBLE`(NUMBER => I, ANSWER => J);  -- This line sets J to 20.{@(J :=^TWICE`(I);@5-- This line also sets J to 20.{@%end PACKAGE_DEMO;{{The package specification must be compiled first, but either the calling{program or the package body may be compiled second.  The calling program{depends only on the package^specification`, not the package^body`.  Similarly,{the package body depends on the package specification.  If the package body{declares any subprograms to be^separate`, these must be compiled after the{package body, because any^separate~subprogram depends on its "parent."{{A package specification that declares no subprograms (only objects, types,{etc.) doesn't need a package body.{{The main program may never be inside a package.  It must be a procedure or{function compiled directly into the library, such as HELLO or ADD.  In most{implementations of Ada, the main program can't have any parameters, and must be{a procedure rather than a function.{}b[ 368B366]A package body may optionally have initialization code, introduced by the word{%begin`.  This code is executed only once, the first time another program{elaborates the package by^with`ing it.  For example, this package uses{initialization code to initialize the array B:{{@/package P is{@2function F return FLOAT;{@/end P;{{@/package body P is{@2A : array(1 .. 10) of FLOAT := (others => 0.0);{@2B : array(1 .. 10, 1 .. 10) of INTEGER;{@2function F return FLOAT is{@5...{@2end F;{@.^begin`{@1^for I in 1 .. 10 loop`{@4^for J in 1 .. 10 loop`{@7^B(I, J) := I*J*J;`{@4^end loop;`{@1^end loop;`{@/end P;{}b[ 369B367]Declarations made inside a package^specification~are said to be^exported~and{are available to programs outside the package that^with~the package.  However,{declarations made inside the package^body~are available only inside the{package.  The package body doesn't even have to be written before outside{programs that^with~the package.  In this example, programs outside and inside{the package may use type ANSWER, array A, and procedure R, but only procedures{P, Q and R may use type QUESTION and array B.  Procedure P may be called only{by Q and R (and itself), and procedure Q is available only to R (and itself).{{@6package X is{@9type ANSWER is (YES, NO, MAYBE);{@9A : array(1 .. 10) of FLOAT;{@9procedure R;{@6end X;{{@6package body X is{@9type QUESTION is (WHY, WHO, HOW);{@9B : array(1 .. 10) of INTEGER;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{}b[ 370B368]@6package X is{@9type ANSWER is (YES, NO, MAYBE);{@9A : array(1 .. 10) of FLOAT;{@9procedure R;{@6end X;{{@6package body X is{@9type QUESTION is (WHY, WHO, HOW);{@9B : array(1 .. 10) of INTEGER;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{{True or False?  In this example, procedure P may call R.{}Please press T for true or F for false, or B to go back.[T371F372B369]@6package X is{@9type ANSWER is (YES, NO, MAYBE);{@9A : array(1 .. 10) of FLOAT;{@9procedure R;{@6end X;{{@6package body X is{@9type QUESTION is (WHY, WHO, HOW);{@9B : array(1 .. 10) of INTEGER;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{{%You're right!~ R is declared in the package specification, so any program{inside X (and any program outside X that^with`s the package) may call R.{}q[ 373B370Q370]@6package X is{@9type ANSWER is (YES, NO, MAYBE);{@9A : array(1 .. 10) of FLOAT;{@9procedure R;{@6end X;{{@6package body X is{@9type QUESTION is (WHY, WHO, HOW);{@9B : array(1 .. 10) of INTEGER;{@9procedure P is separate;{@9procedure Q is separate;{@9procedure R is separate;{@6end X;{{True.  R is declared in the package specification, so any program inside X (and{any program outside X that^with`s the package) may call R.{}q[ 373B370Q370]@9FUNCTIONS WITH INFIX NOTATION{{@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{Ada allows us to overload any of the above operators by enclosing the operator{in quotes following the word^function`.  For example, having defined type DATE,{we may want to define what it means for one date to be "less than" another.  We{could write^function "<"(LEFT, RIGHT : in DATE) return BOOLEAN;`.  Then, our{program could declare^D1, D2 : DATE;~and test^D1 < D2`.  This test would call{our function "<", because^<~is used between two objects of type DATE.{Similarly, we can overload "*" to give the dot product of two vectors:{{@.type VECTOR is array(INTEGER range <>) of FLOAT;{@.V1, V2 : VECTOR(1 .. 100);{@.X : FLOAT;{@-^function "*"(LEFT, RIGHT : in VECTOR) return FLOAT is`{@1...{@-^end "*";`{@....{@-^X := V1 * V2;  -- This calls our function "*".`{}b[ 374B370]@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{There are some restrictions when using infix notation.  First, all of the{operators above (except^abs`,^not`,^+`, and^-`) must be used between two{expressions, and thus the function specification must have exactly two{parameters.  Traditionally, the two parameters are called LEFT and RIGHT.  The{operators^abs~and^not~must have just one expression on the right, and^+~and^-`{may have one expression on the right, or come between two expressions.  These{restrictions come from the way the compiler handles operators.  For example,{the compiler can handle^X := - X;`, but it's not designed to handle^X := * X;`.{{Second, the function "=" must return type BOOLEAN, its two parameters must be{of the same type, and that type must be a limited private type, to be discussed{later.  For all the types discussed so far, function "=" is^already defined~by{Ada.  Two records are equal if all of their corresponding fields are equal, and{two arrays are equal if they have the same length and all of their{corresponding elements are equal.{}b[ 375B373]@1^+@#-@#*@#/@#**@#&@#=@#<@#>@#<=@#>=`{{@4^and@#or@#xor@#abs@#not@#mod@#rem`{{Note that we can't redefine function "/=".  However, if we redefine "=" for{some limited private type, we can use^/=`.  Ada will call our function "=" and{negate the result.  For example,{{@*type TEXT is limited private;  -- to be discussed later{@*T1, T2 : TEXT;{@)^function "="(LEFT, RIGHT : in TEXT) return BOOLEAN is`{@-...{@)^end "=";`{@*...{@*if^T1 /= T2~then ^-- Calls our "=" and reverses the result.`{@-...{@*end if;{{Also, we can't redefine^in`,^not in`,^and then`,^or else`, or^:=`.  Technically,{these aren't operators.{}b[ 376B374]Finally, functions using infix notation can't be compiled directly into the{library.  They must either be declared locally inside a procedure or function,{or placed inside a package.  This is done because many implementations of Ada{create files with names based on the function, procedure, or package being{compiled.  Since many of the operators are punctuation marks, they would create{file names that are illegal on most systems.{{For the same reason, two functions or procedures with the same name can't be{compiled directly into the library; on many systems that would attempt to give{the same name to two different files.  For example, the package specification{below is legal.  However, the package body can't declare both DISPLAYs{%separate`, and it can't declare either "*"^separate`.{{@+package P is{@.type COMPLEX is ...{@.type VECTOR is ...{@-^procedure DISPLAY(C : in COMPLEX);`{@-^procedure DISPLAY(V : in VECTOR);`{@-^function  "*"(LEFT, RIGHT : in COMPLEX) return COMPLEX;`{@-^function  "*"(LEFT, RIGHT : in VECTOR)  return FLOAT;`{@+end P;{}b[ 377B375]@+package K is{@.type COMPLEX is{@1record{@4RE, IM : FLOAT;{@1end record;{@.type VECTOR is array(INTEGER range <>) of FLOAT;{@.function  "+"(LEFT, RIGHT : in COMPLEX) return COMPLEX;{@.function  "*"(LEFT, RIGHT : in COMPLEX) return COMPLEX;{@.function  "*"(LEFT, RIGHT : in VECTOR)  return FLOAT;{@.function  CONJUGATE(C : in COMPLEX) return COMPLEX;{@.procedure DISPLAY(C : in COMPLEX);{@.procedure DISPLAY(V : in VECTOR);{@+end K;{{The above is a package specification.  In the package body, how many{subprograms could be made^separate`:  0, 1, 2, 3, 4, 5, or 6?{}Please press 0, 1, 2, 3, 4, 5, or 6, or B to go back.[2378037913793380438053806380B376]@'package^body~K is{@*function  "+"(LEFT, RIGHT : in COMPLEX) return COMPLEX is ...{@*function  "*"(LEFT, RIGHT : in COMPLEX) return COMPLEX is ...{@*function  "*"(LEFT, RIGHT : in VECTOR)  return FLOAT is ...{@)^function  CONJUGATE(C : in COMPLEX) return COMPLEX is separate;`{@*procedure DISPLAY(C : in COMPLEX) is ...{@)^procedure DISPLAY(V : in VECTOR) is separate;`{@'end K;{{@&^separate (K)`{@&^function CONJUGATE(C : in COMPLEX) return COMPLEX is`{@'...{@&^end CONJUGATE;`{{@&^separate (K)`{@&^procedure DISPLAY(V : in VECTOR) is`{@'...{@&^end DISPLAY;`{{%You're right!~ Only function CONJUGATE and at most one DISPLAY can be made{%separate`.  Functions using infix notation can't be made^separate`, and the name{DISPLAY is overloaded.{}q[ 381B377Q377]@+package K is{@.type COMPLEX is{@1record{@4RE, IM : FLOAT;{@1end record;{@.type VECTOR is array(INTEGER range <>) of FLOAT;{@.function  "+"(LEFT, RIGHT : in COMPLEX) return COMPLEX;{@.function  "*"(LEFT, RIGHT : in COMPLEX) return COMPLEX;{@.function  "*"(LEFT, RIGHT : in VECTOR)  return FLOAT;{@.function  CONJUGATE(C : in COMPLEX) return COMPLEX;{@.procedure DISPLAY(C : in COMPLEX);{@.procedure DISPLAY(V : in VECTOR);{@+end K;{{No, the function CONJUGATE can be made^separate`, because its name isn't{overloaded and it doesn't use infix notation.  Also, one, but not both, DISPLAY{procedures can be made^separate.`{}q[ 381B377Q377]@+package K is{@.type COMPLEX is{@1record{@4RE, IM : FLOAT;{@1end record;{@.type VECTOR is array(INTEGER range <>) of FLOAT;{@.function  "+"(LEFT, RIGHT : in COMPLEX) return COMPLEX;{@.function  "*"(LEFT, RIGHT : in COMPLEX) return COMPLEX;{@.function  "*"(LEFT, RIGHT : in VECTOR)  return FLOAT;{@.function  CONJUGATE(C : in COMPLEX) return COMPLEX;{@.procedure DISPLAY(C : in COMPLEX);{@.procedure DISPLAY(V : in VECTOR);{@+end K;{{No, only function CONJUGATE and at most one DISPLAY can be made^separate`.{Functions using infix notation can't be made^separate`, and the name DISPLAY is{overloaded.{}q[ 381B377Q377]@7INFORMATION HIDING: PRIVATE TYPES{{Information hiding has nothing to do with secrecy; it means containing certain{programming details to a package so that the parts of the program outside the{package can't depend on them.  Thus, when these details change, other parts of{the program aren't affected.{{Let's write the specification (only) for a graphics CRT controller package{without information hiding.  Then we'll improve on it by using a private type.{{The package will let us create arrays in memory representing screens.  We can{create as many of these "virtual screens" as we like, and draw dots, lines, and{boxes on them in memory.  We can also display any virtual screen.  Here's the{package specification:{}b[ 382B377]%package CRT_CONTROLLER is`{  ^type COLOR_TYPE  is (WHITE, BLACK, RED, YELLOW, GREEN, BLUE);`{  ^type SCREEN_TYPE is array(0 .. 299, 0 .. 399) of COLOR_TYPE;`{  ^type POINT is`{@%^record`{@(^ROW@$: INTEGER range 0 .. 299;`{@(^COLUMN : INTEGER range 0 .. 399;`{@%^end record;`{  ^procedure DISPLAY (SCREEN : in SCREEN_TYPE);`{  ^procedure CLEAR@#(SCREEN : in out SCREEN_TYPE; TO: in COLOR_TYPE := BLACK);`{  ^procedure DOT@%(SCREEN : in out SCREEN_TYPE; PLACE : in POINT;`{@5^COLOR : in COLOR_TYPE);`{  ^procedure LINE@$(SCREEN : in out SCREEN_TYPE; FROM, TO : in POINT;`{@5^COLOR : in COLOR_TYPE);`{ ^ procedure BOX@%(SCREEN : in out SCREEN_TYPE; CORNER1, CORNER2 : in POINT;`{@5^COLOR : in COLOR_TYPE);`{%end CRT_CONTROLLER;`{{This package assumes that the resolution of the CRT is 300 vertically by 400{horizontally.  A screen is represented in memory by a two-dimensional array,{each element of which contains one of six possible colors.  Procedures to draw{other figures (circles, etc.) could have been added to the package.{}b[ 383B381]That package specification makes the calling program very clear!  For example,{{@#^with CRT_CONTROLLER; use CRT_CONTROLLER;`{@#^procedure CRT_DEMO is`{@&^S1, S2 : SCREEN_TYPE;`{@#^begin`{@&^CLEAR(S1);`{@&^CLEAR(S2, TO => WHITE);`{@&^LINE(S1, FROM => (150, 100), TO => (150, 300), COLOR => GREEN);`{@&^DOT(S1, PLACE => (150, 200), COLOR => RED);`{@&^DISPLAY(S1);`{@&^BOX(S2, CORNER1 => (240, 100), CORNER2 => (60, 300), COLOR => BLUE);`{@&^DOT(S2, PLACE => (150, 200), COLOR => YELLOW);`{@&^DISPLAY(S2);`{@#^end CRT_DEMO;`{{The first executable line clears memory for screen S1 to all black, because of{the default parameter in the specification of CLEAR.  The next line clears S2{to all white.  The next three lines draw a line and a dot on S1 and display S1.{The program then draws a box and a dot on S2 and displays S2.  Named notation{could optionally have been used for the first parameter of each call, and for{the objects of type POINT, e.g.,^(ROW => 150, COLUMN => 100)`.{}b[ 384B382]At a sacrifice in clarity (not recommended!), the calling program CRT_DEMO{could draw a dot in the center of screen S1 without calling DOT.  Which of the{following statements would accomplish the same thing as{{@4DOT(S1, PLACE => (150, 200), COLOR => RED);{{{@01.  S1(150, 200) := RED;{{@02.  S1(ROW => 150, COLUMN => 200) := RED;{{@03.  Either of the above would work.{}Please press 1, 2, or 3, or B to go back.[138523863386B383]@3^DOT(S1, PLACE => (150, 200), COLOR => RED);`{{{@/^1.  S1(150, 200) := RED;`{{@02.  S1(ROW => 150, COLUMN => 200) := RED;{{@03.  Either of the above would work.{{{%You're right!~ At a sacrifice in clarity, the appropriate element of S1 can be{set directly to RED to draw a dot in the center of the screen.  Number 2 is{wrong because the names ROW and COLUMN apply to type POINT, not to subscripts{of the array.{}q[ 387B384Q384]@4DOT(S1, PLACE => (150, 200), COLOR => RED);{{{@01.  S1(150, 200) := RED;{{@02.  S1(ROW => 150, COLUMN => 200) := RED;{{@03.  Either of the above would work.{{{No, the names ROW and COLUMN apply to type POINT, not to subscripts of the{array.  For this reason number 2 won't compile.{}q[ 387B384Q384]Although the calling program is very clear, there's one disadvantage that can{be eliminated by using a private type: if the resolution of the screen is{changed, the calling program is affected.  For example, the two calls to DOT{are each intended to draw a dot in the center of the screen.  These calls will{have to be changed when the resolution changes, or the dot will no longer be in{the center.  Also, nothing prevents CRT_DEMO from saying^S1(150, 200) := RED;`{directly, instead of calling DOT.  This is a disadvantage, because referencing{the elements of the array directly makes CRT_DEMO very susceptible to changes{in the package.{{It would be better to force CRT_DEMO to call our procedure DOT, and make it{impossible for CRT_DEMO to use the fact the a screen is represented by a{two-dimensional array.  Then the representation of a screen can change without{affecting the correctness of CRT_DEMO.{{We'll improve our package specification and calling program to make SCREEN_TYPE{a^private~type, so that its details can be used only inside the package.  Since{the screen resolution won't be available outside the package, we'll normalize{ROW and COLUMN, making them floating point numbers in the range 0.0 .. 1.0.{}b[ 388B384]Here's our improved package specification:{{package CRT_CONTROLLER is{@#type COLOR_TYPE  is (WHITE, BLACK, RED, YELLOW, GREEN, BLUE);{  ^type SCREEN_TYPE is private;`{@#type POINT is{@&record{@)ROW@$:^FLOAT range 0.0 .. 1.0`;{@)COLUMN :^FLOAT range 0.0 .. 1.0`;{@&end record;{@#procedure DISPLAY (SCREEN : in SCREEN_TYPE);{@#procedure CLEAR@#(SCREEN : in out SCREEN_TYPE; TO: in COLOR_TYPE := BLACK);{@#procedure DOT@%(SCREEN : in out SCREEN_TYPE; PLACE : in POINT;{@6COLOR : in COLOR_TYPE);{@#procedure LINE@$(SCREEN : in out SCREEN_TYPE; FROM, TO : in POINT;{@6COLOR : in COLOR_TYPE);{@#procedure BOX@%(SCREEN : in out SCREEN_TYPE; CORNER1, CORNER2 : in POINT;{@6COLOR : in COLOR_TYPE);{%private`{  ^type SCREEN_TYPE is array(0 .. 299, 0 .. 399) of COLOR_TYPE;`{end CRT_CONTROLLER;{}b[ 389B387]@(package CRT_CONTROLLER is{@+...{@*^type SCREEN_TYPE is private;`{@+procedure DISPLAY (SCREEN : in SCREEN_TYPE);{@+procedure CLEAR@#(SCREEN : in out SCREEN_TYPE; ... );{@+...{@'^private`{@*^type SCREEN_TYPE is array(0 .. 299, 0 .. 399) of COLOR_TYPE;`{@(end CRT_CONTROLLER;{{Outside the package, there are only four things a calling program may do with{objects of a private type like SCREEN_TYPE:{{1. ^Create them:~ S1, S2 : SCREEN_TYPE;{{2. ^Assign them:~ S1 := S2;{{3. ^Test them for equality and inequality:~ if S1 = S2 ...@#if S1 /= S2 ...{{4. ^Use any procedures, functions, and infix operators provided by the package:`{@$CLEAR(S1);@#DISPLAY(S2);@#etc.{}b[ 390B388]@'^With objects of a private type, outside the package we may only:`{^1.  Create@%2.  Assign@%3.  Test  =  /=@%4.  Call package subprograms`{{Note that the calling program, outside the package, can no longer say{%S1(150, 200) := RED;`, because that's not one of the four things listed above.{The calling program is forced to call DOT.  The information that SCREEN_TYPE is{an array can be used by code only^inside~the package.  Of course, the^compiler`{uses this information when compiling code outside or inside the package.{That's why the definition of SCREEN_TYPE must be in the package specification,{not the body.  But the^programmer~isn't allowed to use this information outside{the package.{{%Inside~the package there are no such restrictions.  To write the bodies of the{subprograms, we'll have to use the structure of SCREEN_TYPE and write{statements similar to^S1(150, 200) := RED;`.{{Here's our calling program, revised to agree with the improved package{specification:{}b[ 391B389]@#with CRT_CONTROLLER; use CRT_CONTROLLER;{@#procedure CRT_DEMO is{@&S1, S2 : SCREEN_TYPE;{@#begin{@&CLEAR(S1);{@&CLEAR(S2, TO => WHITE);{@&LINE(S1, FROM => (%0.5`,^0.25`), TO => (%0.5`,^0.75`), COLOR => GREEN);{@&DOT(S1, PLACE => (%0.5`,^0.5`), COLOR => RED);{@&DISPLAY(S1);{@&BOX(S2, CORNER1 => (%0.8`,^0.25`), CORNER2 => (%0.2`,^0.75`), COLOR => BLUE);{@&DOT(S2, PLACE => (%0.5`,^0.5`), COLOR => YELLOW);{@&DISPLAY(S2);{@#end CRT_DEMO;{{Now, if a change is made only to the private part of the package specification,{CRT_DEMO won't have to be revised.  It^will~have to be recompiled, because the{Ada compiler needs the information in the private part of the package{specification.  (The linker won't link with obsolete units, but will tell us{what we must recompile.)  Also, the package body may have to be rewritten.  But{if CRT_DEMO was correct before, it will remain correct without any revision!{The effects of the change are confined to the package.  Containing the effects{of changes by means of information hiding is one of Ada's greatest features.{}b[ 392B390]True or False?  If the private part of a package specification is changed, the{calling program must be recompiled before the package body is recompiled.{}Please press T for true or F for false, or B to go back.[F393T394B391]%You're right!~ The package body and the calling program both depend on the{package specification, but not on each other.  They can be compiled in either{order after the package specification is compiled.{}q[ 395B392Q392]False.  The package body and the calling program don't depend on each other,{but only on the package specification.  Thus they can be compiled in either{order after the package specification is compiled.{}q[ 395B392Q392]If a package exports a constant of a private type, the constant is declared in{the "public" part of the package specification, but it can't be assigned a{value until we get to the private part.  This is called a^deferred constant`.{For example,{{package CRT_CONTROLLER is{@#type COLOR_TYPE  is (WHITE, BLACK, RED, YELLOW, GREEN, BLUE);{@#type SCREEN_TYPE is private;{  ^FLAG_OF_ITALY : constant SCREEN_TYPE;`{@#procedure DISPLAY (SCREEN : in SCREEN_TYPE);{@#...{private{@#type SCREEN_TYPE is array(0 .. 299, 0 .. 399) of COLOR_TYPE;{  ^FLAG_OF_ITALY : constant SCREEN_TYPE :=`{@&^(others => (0 .. 132 => GREEN, 133 .. 266 => WHITE, 267 .. 399 => RED));`{end CRT_CONTROLLER;{{CRT_DEMO could then say^S1 := FLAG_OF_ITALY;~or^DISPLAY(FLAG_OF_ITALY);`.{}b[ 396B392]@6TYPE TEXT AND LIMITED PRIVATE TYPES{{Earlier we remarked that Ada strings are of fixed length.  Section 7.6 of the{LRM suggests that we create a type TEXT to get around this restriction.{Instead of declaring objects to be STRINGs, we'll declare them to be of type{TEXT, which will simulate variable-length strings.  Then we'll see how this{creates a need for limited private types.{{The package specification in section 7.6 of the LRM makes use of discriminated{records.  Since we haven't yet covered that topic, we'll give a simplified{presentation here.  Let's declare{{@3^type TEXT is`{@6^record`{@9^LEN : INTEGER range 0 .. 80 := 0;`{@9^VAL : STRING(1 .. 80);`{@6^end record;`{{Any appropriate maximum length may be used in place of 80.  It isn't necessary{to initialize the VAL field to all blanks, because the LEN field keeps track of{how much of the VAL field is significant.  The LEN field is given a default{value of 0, so that objects of type TEXT will be initialized to zero length.{}b[ 397B395]@3^type TEXT is`{@6^record`{@9^LEN : INTEGER range 0 .. 80 := 0;`{@9^VAL : STRING(1 .. 80);`{@6^end record;`{{For example, we could declare^T1 : TEXT;`.  We could then set^T1.LEN := 5;~and{%T1.VAL(1 .. 5) := "Hello";`.  The fact that the last 75 characters of T1.VAL{might contain garbage is of no consequence, because T1.LEN tells our program{to consider only the first 5 characters of T1.VAL.  Since T1.LEN is a variable,{we've simulated variable-length strings.{{A minor disadvantage is that, for each object of type TEXT, we reserve enough{memory for the longest possible length (80 in this example).  Discriminated{records, to be covered in the Advanced Topics section, can overcome this{disadvantage.{}b[ 398B396]Type TEXT will be much easier to use if we write some subprograms.  First, we{need to convert between types TEXT and STRING.  Conversion in both directions{is very simple:{{@2^function STR(T : in TEXT) return STRING is`{@2^begin`{@5^return T.VAL(1 .. T.LEN);`{@2^end STR;`{{@2^function TXT(S : in STRING) return TEXT is`{@5^ANSWER : TEXT;`{@2^begin`{@5^ANSWER.LEN := S'LENGTH;`{@5^ANSWER.VAL(1 .. ANSWER.LEN) := S;`{@5^return ANSWER;`{@2^end TXT;`{{Now we can write, for example,^T1 : TEXT := TXT("Hello");~and we don't even{have to count the characters of "Hello".  Later, the program might execute{%T1 := TXT("Type TEXT is very convenient.");~showing that T1 simulates a{variable-length string.  If we^with~and^use~TEXT_IO in our program, we can{write^PUT_LINE(STR(T1));`.{}b[ 399B397]It would be convenient to overload the^&~operator to concatenate two TEXTs, or{a TEXT with a STRING.  We can also overload four of the relational operators:{{@%^function "&"  (LEFT, RIGHT : in TEXT)@/return TEXT;`{@%^function "&"  (LEFT : in TEXT;@#RIGHT : in STRING) return TEXT;`{@%^function "&"  (LEFT : in STRING; RIGHT : in TEXT)@#return TEXT;`{@%^function "<"  (LEFT, RIGHT : in TEXT)@/return BOOLEAN;`{@%^function ">"  (LEFT, RIGHT : in TEXT)@/return BOOLEAN;`{@%^function "<=" (LEFT, RIGHT : in TEXT)@/return BOOLEAN;`{@%^function ">=" (LEFT, RIGHT : in TEXT)@/return BOOLEAN;`{{The bodies of these subprograms are very simple!  For example:{{@,^function "&"(LEFT, RIGHT : in TEXT) return TEXT is`{@,^begin`{@/^return TXT(STR(LEFT) & STR(RIGHT));`{@,^end "&";`{{@,^function "<"(LEFT, RIGHT : in TEXT) return BOOLEAN is`{@,^begin`{@/^return STR(LEFT) < STR(RIGHT);`{@,^end "<";`{}b[ 400B398]@3function TXT(S : in STRING) return TEXT is{@6ANSWER : TEXT;{@3begin{@6ANSWER.LEN := S'LENGTH;{@6ANSWER.VAL(1 .. ANSWER.LEN) := S;{@6return ANSWER;{@3end TXT;{{{True or False?  A call to TXT with the null string,^TXT("")`, will raise a{CONSTRAINT_ERROR.{}Please press T for true or F for false, or B to go back.[F401T402B399]@2^function TXT(S : in STRING) return TEXT is`{@5^ANSWER : TEXT;`{@2^begin`{@5^ANSWER.LEN := S'LENGTH;`{@5^ANSWER.VAL(1 .. ANSWER.LEN) := S;`{@5^return ANSWER;`{@2^end TXT;`{{{%You're right!~ The first executable statement will set ANSWER.LEN to 0, and{the second executable statement will do nothing.  The check for{CONSTRAINT_ERROR is suppressed when a null slice is involved.  Thus the{function will work correctly even for the null string.{}q[ 403B400Q400]@3function TXT(S : in STRING) return TEXT is{@6ANSWER : TEXT;{@3begin{@6ANSWER.LEN := S'LENGTH;{@6ANSWER.VAL(1 .. ANSWER.LEN) := S;{@6return ANSWER;{@3end TXT;{{{False.  The function will work correctly even for the null string.  The first{executable statement will set ANSWER.LEN to 0, and the second executable{statement will do nothing.  The check for CONSTRAINT_ERROR is suppressed when a{null slice is involved.{}q[ 403B400Q400]@4type TEXT is{@7record{@:LEN : INTEGER range 0 .. 80 := 0;{@:VAL : STRING(1 .. 80);{@7end record;{{There are two problems with type TEXT.  The way Ada assigns arrays is less than{ideal when assigning objects of type TEXT, and the way Ada tests for equality{is totally unacceptable.  Suppose we have^T1, T2 : TEXT;~and then we execute{%T1 := TXT("Hello");~and then^T2 := T1;`.  In doing the assignment, Ada will{copy all 80 characters of T1.VAL, even though the last 75 characters contain{garbage and only the first 5 characters (and the LEN field) need be copied.{Perhaps we could live with this inefficiency, but Ada's test for equality of{arrays creates a more serious problem.{{If we write^T1 := TXT("aaaaaaaaaa");~and^T2 := TXT("bbbbbbbbbb");~and then{%T1 := TXT("Hello");~and^T2 := TXT("Hello");`, Ada will say that T1 /= T2,{because it compares the entire VAL fields:  T1.VAL(6 .. 10) is "aaaaa", but{T2.VAL(6 . .10) is "bbbbb".  We want Ada to compare only the first 5 characters{of T1 and T2, as both LEN fields are 5.  We could modify function TXT (that{converts from STRING to TEXT) to pad the rest of the VAL field with blanks, so{that the test for equality would be correct, but that would reduce efficiency.{}b[ 404B400]We could also try to get around this problem by writing our own function EQUAL:{{@/function EQUAL(T1, T2 : in TEXT) return BOOLEAN is{@/begin{@2return STR(T1) = STR(T2);{@/end EQUAL;{{This function would work, but we might forget to write^if EQUAL(T1, T2)~and{write^if T1 = T2~instead.  Similarly, we could write a procedure to assign{TEXTs efficiently, and forget to use it and write^T2 := T1;`.  But Ada will{prevent us from assigning TEXTs and testing them for equality if we create a{package and make type TEXT^limited private`.  Outside the package there are{only^two~things we may do with objects of a limited private type:{{1. ^Create them:~ T1, T2 : TEXT;{{2. ^Use any procedures, functions, and infix operators provided by the package:`{@$T1 & T2@#etc.{{We can't test for equality and inequality unless the package includes a{function "=".  Also, Ada won't let us write^T2 := T1;`, but the package could{provide a procedure to assign TEXTs.  Here's our package specification:{}b[ 405B403]@-package TEXT_HANDLER is{@/^type TEXT is limited private;`{@0function STR(T : in TEXT) return STRING;{@0function TXT(S : in STRING) return TEXT;{@0function "&"(LEFT, RIGHT : in TEXT) return TEXT;{@0...{@/^function "="(LEFT, RIGHT : in TEXT) return BOOLEAN;`{@0function "<"(LEFT, RIGHT : in TEXT) return BOOLEAN;{@0...{@/^procedure SET(TARGET : in out TEXT; TO : in TEXT);`{@,^private`{@0type TEXT is{@3record{@6LEN : INTEGER range 0 .. 80 := 0;{@6VAL : STRING(1 .. 80);{@3end record;{@-end TEXT_HANDLER;{{Note that we write^type TEXT is limited private`, but we still introduce the{private part of the package simply with the word^private`.{{The two new subprograms are as easy to write as the others:{}b[ 406B404]@,^function "="(LEFT, RIGHT : in TEXT) return BOOLEAN is`{@,^begin`{@/^return STR(LEFT) = STR(RIGHT);`{@,^end "=";`{{@,^procedure SET(TARGET : in out TEXT; TO : in TEXT) is`{@,^begin`{@/^TARGET.LEN := TO.LEN;`{@/^TARGET.VAL(1 .. TARGET.LEN) := TO.VAL(1 .. TO.LEN);`{@,^end SET;`{{In summary, we used^limited private~for type TEXT because Ada's definitions of{equality and assignment weren't appropriate for that type, and we wanted to{provide our own definitions.  However, Ada's definitions^were~appropriate for{SCREEN_TYPE, so we made that a^private~type to contain the effects of changes.{}b[ 407B405]@+package STACKS is{@.type STACK is^?`{@.procedure PUSH (S : in out STACK; ITEM : in  INTEGER);{@.procedure POP  (S : in out STACK; ITEM : out INTEGER);{@+private{@.type IVECTOR is array(INTEGER range <>) of INTEGER;{@.type STACK is{@1record{@4SP : INTEGER range 1 .. 11 := 1;{@4ST : IVECTOR(1 .. 10);{@1end record;{@+end STACKS;{{Suppose we want to write a package that lets us create objects of type STACK,{and PUSH and POP integers on them.  The stacks will be last in, first out.{(For now, ignore the possibilities of stack underflow and overflow.)  Should{type STACK be^private~or^limited private`?{{@31.  Type STACK should be^private`.{{@32.  Type STACK should be^limited private`.{}Please press 1 or 2, or B to go back.[24081409B406]@+package STACKS is{@-^type STACK is limited private;`{@.procedure PUSH (S : in out STACK; ITEM : in  INTEGER);{@.procedure POP  (S : in out STACK; ITEM : out INTEGER);{@+private{@.type IVECTOR is array(INTEGER range <>) of INTEGER;{@-^type STACK is`{@0^record`{@3^SP : INTEGER range 1 .. 11 := 1;`{@3^ST : IVECTOR(1 .. 10);`{@0^end record;`{@+end STACKS;{{%You're right!~ Similar to type TEXT, only part of the array in type STACK (the{part up through SP - 1) is significant; the rest contains garbage.  Thus, Ada's{test for equality is unsatisfactory for the same reason, and type STACK should{be^limited private`.{}q[ 410B407Q407]@+package STACKS is{@.type STACK is^?`{@.procedure PUSH (S : in out STACK; ITEM : in  INTEGER);{@.procedure POP  (S : in out STACK; ITEM : out INTEGER);{@+private{@.type IVECTOR is array(INTEGER range <>) of INTEGER;{@.type STACK is{@1record{@4SP : INTEGER range 1 .. 11 := 1;{@4ST : IVECTOR(1 .. 10);{@1end record;{@+end STACKS;{{No, type STACK is similar to type TEXT in that only part of the array (the part{up through SP - 1) is significant; the rest contains garbage.  Thus, Ada's test{for equality is unsatisfactory for the same reason, and type STACK should be{%limited private`.{}q[ 410B407Q407]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@H^>  ADDITIONAL TYPES, EXCEPTIONS,`{@#Simple Declarations and Simple@-^TEXT_IO, AND ASSIGNMENT 5`{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 411B407]@BACCESS TYPES{{Access types are sometimes called "pointers" in other languages.  However, the{name "pointer" fell into disrepute, because of "dangling reference" problems.{With Ada's access types, dangling references are impossible, unless we{deliberately instantiate UNCHECKED_DEALLOCATION (discussed in the Advanced{Topics section).  So Ada uses the reserved word^access`.{{If we define type DATE as before, and write^USA : DATE;~then USA has three{fields: DAY, MONTH, and YEAR.  However, if we write{{@<^type P is access DATE;`{@<^D1, D2 : P;`{{then D1 and D2 are capable of^pointing to~objects of type DATE.  In most{implementations of Ada, this means that D1 and D2 can each contain the machine{address of the start of a record of type DATE.  However, this detail depends on{the implementation of Ada.  D1 and D2 themselves don't have fields, but the{objects they can point to have fields.{}b[ 412B410]@<^type P is access DATE;`{@<^D1, D2 : P;`{{At present D1 and D2 point to nothing.  However, if we execute^D1 := new DATE;`,{then, at run time, enough memory for one record of type DATE is allocated, and{D1 is made to point to it.  This new object of type DATE doesn't have a name;{only the pointer, D1, has a name.  By contrast, when we elaborate^USA : DATE;`{we create an object that has a name (USA), but nothing can point to it.{{We can refer to the fields of the nameless object pointed to by D1 as if D1{itself had fields.  Thus, we can write D1.DAY, D1.MONTH, and D1.YEAR, and use{these on either side of an assignment:^D1.DAY := 12;`.  The entire object{pointed to by D1 is^D1.all`, so we could write^D1.all := (12, OCT, 1492);`.  Note{that^D1.DAY~is simply an abbreviation for^D1.all.DAY`.  Similarly, if A1 points{to an array rather than a record, then^A1.all(5)~may be abbreviated^A1(5)`.{{We can execute^D2 := new DATE'(4, JUL, 1776);~giving the new object a value{when it's created.  We can also declare^D3 : P := new DATE;~to make D3 point to{an object when D3 is created, or even write^D3 : P := new DATE'(4, JUL, 1776);`{to make D3 point to an object and also give the object a value.{}b[ 413B411]We can write^D3 := null;~to make D3 point nowhere.  When a pointer is declared{and no initialization is shown, it's automatically initialized to^null`, so{%D4 : P;~means^D4 : P := null;`.  When a pointer is null, trying to reference the{object pointed to (%D4.DAY~or^D4.all`, etc.) will raise a CONSTRAINT_ERROR.  We{can test to see if a pointer is null:^if D4 = null then~...^end if;`.{{Copying a pointer isn't the same as copying the object pointed to.  If we{execute^D1.all := (12, OCT, 1492);~and then^D2.all := D1.all;`, the entire{record is copied.  If we change D1.DAY with^D1.DAY := 13;`, D2.DAY is still 12.{{However, is we execute^D1.all := (12, OCT, 1492);~and then^D2 := D1;`, then the{address in D1 is copied to D2, so that D2 now points to the same place as D1.{Thus, if we change D1.DAY with^D1.DAY := 13;`, then D2.DAY is also 13, because{it references the same memory location.{{If we have^D1 := new DATE'(12, OCT, 1492);~and^D2 := new DATE'(4, JUL, 1776);`{and then execute^D2 := D1;`, D2 now points where D1 points, and nothing any{longer points to the object containing (4, JUL, 1776).  Most systems will later{reclaim the memory occupied by that object, if the memory is needed.  This{process is called^garbage collection`.  It's automatic, and normally need not{concern the programmer.{}b[ 414B412]A simple^linked list~can be thought of as a chain.  Each link contains some{useful data (perhaps an integer, perhaps pages of information), and a pointer{to the next item in the chain.  There's also a pointer, usually called HEAD,{that points to the first link in the chain.  The last link points nowhere.{{A linked list of integers might look something like this:{@'^ ____@'__________@*__________@*__________ `{@'^|  --|---->| INT@#10 |@#,--->| INT@#27 |@#,--->| INT@#34 |`{@'^|____|@%| NEXT  ---|---'@$| NEXT  ---|---'@$| NEXT null|`{@'^ HEAD@&|__________|@(|__________|@(|__________|`{{To add another integer to the chain, keeping the integers in ascending order,{we simply break the chain at the appropriate point and insert another link.{{To set up our linked list, we'd like to write^type P is access LINK;~and write{{@<^type LINK is`{@?^record`{@B^INT  : INTEGER;`{@B^NEXT : P;`{@?^end record;`{}b[ 415B413]However, the declaration of type P involves LINK, and the declaration of type{LINK involves P, so neither declaration can come first!  Ada provides a special{means of solving this problem.  We can write{{@<^type LINK;`{@<^type P is access LINK;`{@<^type LINK is`{@?^record`{@B^INT  : INTEGER;`{@B^NEXT : P;`{@?^end record;`{{The first line is called an^incomplete type declaration`.  It simply tells the{compiler that type LINK exists.  That's all the information the compiler needs{to compile the second line.  The second line tells the compiler that objects of{type P will contain pointers, but for this line the compiler doesn't need to{know details of the objects pointed to.  The second line must be followed by{the full declaration of type LINK.{}b[ 416B414]@4type PERSON is{@7record{@:NAME : STRING(1 .. 10);{@:AGE  : NATURAL;{@7end record;{@4type P is access PERSON;{@4P1 : P := new PERSON'("Susan@%", 21);{@4P2 : P := new PERSON'("John@&", 35);{@4...{@4P2 := P1;{@4P1.AGE := 22;{{{@?What is P2.AGE?{{@?1.  P2.AGE is 21.{{@?2.  P2.AGE is 22.{{@?3.  P2.AGE is 35.{}Please press 1, 2, or 3, or B to go back.[241714183418B415]@4type PERSON is{@7record{@:NAME : STRING(1 .. 10);{@:AGE  : NATURAL;{@7end record;{@4type P is access PERSON;{@4P1 : P := new PERSON'("Susan@%", 21);{@4P2 : P := new PERSON'("John@&", 35);{@4...{@4P2 := P1;{@4P1.AGE := 22;{{{%You're right!~ The last line changed P1.AGE to 22.  Since the previous line{made P2 point where P1 points, P2.AGE is also 22.{}q[ 419B416Q416]@4type PERSON is{@7record{@:NAME : STRING(1 .. 10);{@:AGE  : NATURAL;{@7end record;{@4type P is access PERSON;{@4P1 : P := new PERSON'("Susan@%", 21);{@4P2 : P := new PERSON'("John@&", 35);{@4...{@4P2 := P1;{@4P1.AGE := 22;{{{No, the last line changed P1.AGE to 22.  Since the previous line made P2 point{where P1 points, P2.AGE is also 22.{}q[ 419B416Q416]Let's use an access type to write a program that gets integers in random order{from the keyboard, maintaining a linked list of them.  When^0~is input, the{program outputs the integers in ascending order.  This program will be a good{stepping-stone to Outside Assignment 5.  To simplify inserting an integer into{the linked list, HEAD will point to an unused LINK, which will in turn point to{the first actual link in the chain:{{% ____@&__________@)__________@)__________@)__________ `{%|  --|--->| INT@&|@#,-->| INT@#10 |@#,-->| INT@#27 |@#,-->| INT@#34 |`{%|____|@$| NEXT  ---|---'@#| NEXT  ---|---'@#| NEXT  ---|---'@#| NEXT null|`{% HEAD@%|__________|@'|__________|@'|__________|@'|__________|`{{We could create our linked list using arrays rather than an access type.{However, we'd have to specify the size of the arrays, placing a limit on the{number of integers the program can handle.  With the access type, the only{limit is the amount of available memory.  We'll be able to move our program to{a larger machine to increase this limit, without changing any code - not even{one line to specify the size of an array.{{Here's our program ...{}b[ 420B416]@(with TEXT_IO; use TEXT_IO;{@(procedure LL_DEMO is{@+package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@+type LINK;{@+type P is access LINK;{@+type LINK is{@.record{@1INT  : INTEGER;{@1NEXT : P;{@.end record;{@*^HEAD : P := new LINK;`{@*^I@$: INTEGER;`{@*^procedure ADD_I_TO_LINKED_LIST is separate;`{@*^procedure DISPLAY_LINKED_LIST is separate;`{@(begin{@*^PUT("Type an integer: ");  GET(I);  SKIP_LINE;`{@*^while I /= 0 loop`{@-^ADD_I_TO_LINKED_LIST;`{@-^PUT("Type an integer: ");  GET(I);  SKIP_LINE;`{@*^end loop;`{@*^DISPLAY_LINKED_LIST;`{@(end LL_DEMO;{}b[ 421B419]^separate (LL_DEMO)`{^procedure DISPLAY_LINKED_LIST is`{@#^TMP : P := HEAD.NEXT;@*-- Skip unused link at the head of the list.`{^begin`{@#^while TMP /= null loop`{@&^PUT(TMP.INT);  NEW_LINE;@)-- Display integer in the current link.`{@&^TMP := TMP.NEXT;@9-- Go to next link in the list.`{@#^end loop;`{^end DISPLAY_LINKED_LIST;`{{^separate (LL_DEMO)`{^procedure ADD_I_TO_LINKED_LIST is`{@#^TMP : P := HEAD;@'-- Begin search of where to insert at start of list.`{^begin`{@#^while TMP /= null and then TMP.NEXT /= null and then TMP.NEXT.INT < I loop`{@&^TMP := TMP.NEXT;  -- Note use of "and then" to avoid trying to reference`{@#^end loop;@,-- the object pointed to when the pointer is null.`{@#^TMP.NEXT := new LINK'(I, TMP.NEXT);  -- Create new link and insert in list.`{^end ADD_I_TO_LINKED_LIST;`{{The best way to follow these two subprograms is to draw a linked list on a{piece of scrap paper and "hand execute" the subprograms.{}b[ 422B420]@3type LINK; ^-- 1`{@3type P is access LINK;{@3type LINK is{@6record{@9F : FLOAT; ^-- 2`{@9S : STRING(1 .. 10); ^-- 3`{@9A : array(1 .. 10) of INTEGER; ^-- 4`{@6end record;{@3L1 : LINK; ^-- 5`{@3P1 : P;{{Which commented line in the above is^illegal`?{}Please press 1, 2, 3, 4, or 5, or B to go back.[44231424242534265427B421]@3type LINK;  -- 1{@3type P is access LINK;{@3type LINK is{@6record{@9F : FLOAT;  -- 2{@9S : STRING(1 .. 10);  -- 3{@8^A : array(1 .. 10) of INTEGER;  -- 4`{@6end record;{@3L1 : LINK;  -- 5{@3P1 : P;{{{%You're right!~ Inside a record definition, the name of a field must be{followed by a type name, not^array`.  We would first have to say something like{%type LIST is array(INTEGER range <>) of INTEGER;`, and then change the field{definition to{{@8^A : LIST(1 .. 10);`{}q[ 428B422Q422]@3type LINK;  -- 1{@3type P is access LINK;{@3type LINK is{@6record{@9F : FLOAT;  -- 2{@9S : STRING(1 .. 10);  -- 3{@9A : array(1 .. 10) of INTEGER;  -- 4{@6end record;{@3L1 : LINK;  -- 5{@3P1 : P;{{{No, the first line is legal.  Ada allows an incomplete type declaration to{precede the declaration of an access type, provided the complete type{declaration follows.{}q[ 428B422Q422]@3type LINK;  -- 1{@3type P is access LINK;{@3type LINK is{@6record{@9F : FLOAT;  -- 2{@9S : STRING(1 .. 10);  -- 3{@9A : array(1 .. 10) of INTEGER;  -- 4{@6end record;{@3L1 : LINK;  -- 5{@3P1 : P;{{{No, the declaration of F inside the record definition is legal, because Ada{records may contain fields of any type.{}q[ 428B422Q422]@3type LINK;  -- 1{@3type P is access LINK;{@3type LINK is{@6record{@9F : FLOAT;  -- 2{@9S : STRING(1 .. 10);  -- 3{@9A : array(1 .. 10) of INTEGER;  -- 4{@6end record;{@3L1 : LINK;  -- 5{@3P1 : P;{{{No, the declaration of S inside the record definition is legal, because Ada{records may contain fields of any type.{}q[ 428B422Q422]@3type LINK;  -- 1{@3type P is access LINK;{@3type LINK is{@6record{@9F : FLOAT;  -- 2{@9S : STRING(1 .. 10);  -- 3{@9A : array(1 .. 10) of INTEGER;  -- 4{@6end record;{@3L1 : LINK;  -- 5{@3P1 : P;{{{No, the declaration of L1 as type LINK is legal.  Even though type P was{declared to be^access LINK~and we ordinarily would declare objects to be of{type P, we may also directly declare objects to be of type LINK.  Of course,{nothing can point to such objects.{}q[ 428B422Q422]@7USER DEFINED TYPES AND PORTABILITY{{In some implementations of Ada, INTEGERs are represented by 32-bit two's{complement numbers, giving the range -2_147_483_648 .. 2_147_483_647.  Other{implementations use 16-bit two's complement INTEGERs, giving the range{-32768 .. 32767.  However, some of the 16-bit implementations also provide a{32-bit type called LONG_INTEGER.{{Suppose we need a variable called NUMBER to count from zero to one million.  We{could declare^NUMBER: INTEGER;~for the 32-bit implementation, and change this{to^NUMBER : LONG_INTEGER;~when we port the program to a machine running a{16-bit version that provides LONG_INTEGER.  However, we could also declare{{@4^type COUNTER is range 0 .. 1_000_000;`{@4^NUMBER : COUNTER;`{{and both implementations of Ada will automatically select the appropriate{internal representation for our type COUNTER!  The 32-bit Ada will select{INTEGER, and the 16-bit Ada will select LONG_INTEGER.  This gives us the{advantage that no code has to be changed when the program is ported.  COUNTER{is called a^user-defined type`.  Of course, we must use explicit type{conversion to mix objects of type COUNTER with objects of other types.{}b[ 429B422]Similarly, different implementations of Ada provide different representations{for type FLOAT, and some provide a type LONG_FLOAT.  We can declare{{@<^type REAL is digits 8;`{@<^F : REAL;`{{and be certain that F will have at least 8 digits of accuracy on any machine{that accepts this type declaration.  A range constraint is optional.{{User defined types also apply to fixed point numbers; these will be discussed{in the Advanced Topics section.{{It's possible to make a declaration that will be accepted by only some{implementations of Ada.  For example, if we declare{{@3^type X is digits 30 range 0.0 .. 100.0;`{{some implementations of Ada might have to report that there's no available type{that gives at least 30 digits of accuracy.{{No language can give perfectly portable programs, but Ada truly advanced the{state of the art in portability.{}b[ 430B428]@ADERIVED TYPES{{Derived types are created to prevent accidental mixing of objects.  Unlike{subtypes, derived types are distinct types.  For example,{{@.^type NO_OF_APPLES  is new INTEGER;`{@.^type NO_OF_ORANGES is new INTEGER range 0 .. 100;`{@.^NOA : NO_OF_APPLES;`{@.^NOO : NO_OF_ORANGES;`{@.^I@#: INTEGER;`{@/...{@.^NOA := NOA + NOO;  -- illegal`{@.^NOA := NOA + NOA;`{@.^NOA := NOA + I;  -- illegal`{@.^NOA := NOA + NO_OF_APPLES(I);`{@.^NOA := NOA + NO_OF_APPLES(NOO);`{{A derived type is denoted by the reserved word^new~followed by an existing type{like INTEGER.  The operations that Ada knows for INTEGERs, such as addition,{are "inherited" by the derived types so that, for example, Ada knows how to add{two objects of type NO_OF_ORANGES.  As the examples above show, we can't mix{types accidentally, but we can deliberately mix them by converting first.{}b[ 431B429]In summary,{{{@*^Subtypes~are usually created to provide range constraints:{{@0^subtype DAY_SUBTYPE is INTEGER range 1 .. 31;`{{{@'^Derived types~are usually created to prevent accidental mixing:{{@3^type NO_OF_APPLES  is new INTEGER;`{@3^type NO_OF_ORANGES is new INTEGER~...^;`{{{@)^User-defined types~are usually created to gain portability:{{@4^type COUNTER is range 0 .. 1_000_000;`{@4^type REAL@$is digits 8;`{}b[ 432B430] type METERS@,is new FLOAT;{ type SECONDS@+is new FLOAT;{ type METERS_PER_SECOND is new FLOAT;{ ...{ function "*"(LEFT : in METERS_PER_SECOND; RIGHT : in SECONDS) return METERS is{ begin{@$return METERS(LEFT) * METERS(RIGHT);{ end "*";{ function "*"(LEFT : in SECONDS; RIGHT : in METERS_PER_SECOND) return METERS is{ begin{@$return RIGHT * LEFT;{ end "*";{ function "/"(LEFT : in METERS; RIGHT : in SECONDS) return METERS_PER_SECOND is{ begin{@$return METERS_PER_SECOND(LEFT) / METERS_PER_SECOND(RIGHT);{ end "/";{{@1The above program segment is an example of ...{@11.  derived types.{@12.  user-defined types.{@13.  subtypes.{}Please press 1, 2, or 3, or B to go back.[143324343435B431] type METERS@,is^new~FLOAT;{ type SECONDS@+is^new~FLOAT;{ type METERS_PER_SECOND is^new~FLOAT;{{{%You're right!~ The reserved word^new~in the segment above tells us that we're{defining derived types.{}q[ 436B432Q432] type METERS@,is new FLOAT;{ type SECONDS@+is new FLOAT;{ type METERS_PER_SECOND is new FLOAT;{{{No, examples of user-defined types are{{@5type COUNTER is range 0 .. 1_000_000;{@5type REAL@$is digits 8;{}q[ 436B432Q432] type METERS@,is new FLOAT;{ type SECONDS@+is new FLOAT;{ type METERS_PER_SECOND is new FLOAT;{{{No, subtypes are usually created to provide range constraints.{}q[ 436B432Q432]@CEXCEPTIONS{{When an error occurs during the elaboration or execution of a statement, Ada is{said to^raise an exception`.  Ordinarily this stops the program, but Ada{programs can trap exceptions and execute a special block of code when one{occurs.  This code is called an^exception handler`.{{We can define our own exceptions, but five of them are predefined by Ada:{{%CONSTRAINT_ERROR`{@%This is the exception encountered most often by beginners, because it can{be caused by a number of different things.  It can be raised by a subscript out{of range, a subtype out of range (USA.DAY := 32;), an attribute used improperly{(INTEGER'VALUE("12X3") or MONTH_TYPE'VAL(13)), assigning an array of one length{to a destination of another (H : STRING(1 .. 5) := "Hi";), or by attempting to{access an object with a null pointer.  The newest versions of Ada also raise{CONSTRAINT_ERROR on an arithmetic overflow or an attempt to divide by zero.{{%NUMERIC_ERROR`{@%Many implementations of Ada raise this on an arithmetic overflow or an{attempt to divide by zero.  The newest implementations of Ada raise{CONSTRAINT_ERROR instead.{}b[ 437B432]%PROGRAM_ERROR`{@%This is rarely encountered by beginners, but it can be raised by skipping{around the^return~statement in a function and running into the^end~statement.{{%STORAGE_ERROR`{@%This is raised by running out of memory, as with a recursive program{calling itself unconditionally or an attempt to create an infinitely large{linked list.{{%TASKING_ERROR`{@%This will be discussed in the section on Tasking.{{An exception handler is introduced by the reserved word^exception`; its{structure is similar to that of a^case~construct.  We'll see an example in a{moment.  Unlike a^case~construct, an exception handler need not account for all{the possibilities.{{An exception handler can be placed in a subprogram, in the initialization code{of a package, in a task (to be discussed in the section on Tasking), or in a{block (to be discussed later in this section).  Here's a procedure with an{exception handler that handles an exception,^WRONG`, that we declare ourselves,{as well as the built-in exceptions^CONSTRAINT_ERROR~and^NUMERIC_ERROR`:{}b[ 438B436] with TEXT_IO; use TEXT_IO;{ procedure EXCEPTION_DEMO is{@$package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@$I@%: INTEGER;{@#^WRONG : exception;`{ begin{@$loop{@'NEW_LINE(2);  PUT("Type a positive integer. ");  GET(I);  SKIP_LINE;{@'if I <= 0 then{@)^raise WRONG;`{@'end if;{@'PUT("The square is ... ");{@&^PUT(I*I); -- Raises CONSTRAINT_ERROR or NUMERIC_ERROR if I is too large.`{@$end loop;{^exception`{@#^when CONSTRAINT_ERROR | NUMERIC_ERROR =>`{@'PUT(" ... too big.");{@#^when WRONG =>`{@'NEW_LINE;{@'PUT("I said POSITIVE integer!");{ end EXCEPTION_DEMO;{}b[ 439B437]We can deliberately raise an exception (either user-defined or built-in) with{the^raise~statement, as in^raise WRONG;~or^raise CONSTRAINT_ERROR;`.  Also,{ordinary statements can raise exceptions.  In our sample program,^PUT(I*I);`{raises CONSTRAINT_ERROR or NUMERIC_ERROR if I is too large.  When an executable{statement raises an exception, the exception handler is executed^instead of~the{rest of the procedure, function, etc.  Our program keeps asking for integers{and displaying their squares until an exception is raised.  Then, the exception{handler is executed, and there's no way to get back into the procedure to ask{for another integer (short of a recursive call).  Even a^goto~from the{exception handler to the main part of the procedure is forbidden.  Soon we'll{show how the block construct can overcome this problem, so that our program{will continue to ask for more integers even after an exception is handled.{{As with^case~constructs, an exception handler may use the vertical bar to{denote multiple choices (%when CONSTRAINT_ERROR | NUMERIC_ERROR =>~block of{code), and it may say^when others =>~to handle all cases not covered earlier.{But there's no way to test, inside the exception handler,^which line~raised the{exception.  We can only test^which kind~of exception was raised.{{Don't use exceptions where a simple^if~will do.  In our program, trapping the{arithmetic overflow was OK, but the^if~could have handled I <= 0 without{raising WRONG.  This exception was declared only to give a simple example.{}b[ 440B438]@>1.  CONSTRAINT_ERROR{{@>2.  NUMERIC_ERROR{{@>3.  PROGRAM_ERROR{{@>4.  STORAGE_ERROR{{@>5.  TASKING_ERROR{{{Assuming RAINBOW_COLOR and TRAFFIC_LIGHT_COLOR are defined as before, which of{the above exceptions would be raised by^RAINBOW_COLOR'VALUE("AMBER")`?{}Please press 1, 2, 3, 4, or 5, or B to go back.[14412442344344445445B439]@=^1.  CONSTRAINT_ERROR`{{@>2.  NUMERIC_ERROR{{@>3.  PROGRAM_ERROR{{@>4.  STORAGE_ERROR{{@>5.  TASKING_ERROR{{{%You're right!~ Using an attribute improperly in this way will raise{CONSTRAINT_ERROR.{}q[ 446B440Q440]@>1.  CONSTRAINT_ERROR{{@>2.  NUMERIC_ERROR{{@>3.  PROGRAM_ERROR{{@>4.  STORAGE_ERROR{{@>5.  TASKING_ERROR{{{No, NUMERIC_ERROR is usually raised by arithmetic overflow, or attempted{division by zero.{}q[ 446B440Q440]@>1.  CONSTRAINT_ERROR{{@>2.  NUMERIC_ERROR{{@>3.  PROGRAM_ERROR{{@>4.  STORAGE_ERROR{{@>5.  TASKING_ERROR{{{No, PROGRAM_ERROR is usually raised by skipping around the^return~statement in{a function.{}q[ 446B440Q440]@>1.  CONSTRAINT_ERROR{{@>2.  NUMERIC_ERROR{{@>3.  PROGRAM_ERROR{{@>4.  STORAGE_ERROR{{@>5.  TASKING_ERROR{{{No, STORAGE_ERROR is raised by running out of memory.{}q[ 446B440Q440]@>1.  CONSTRAINT_ERROR{{@>2.  NUMERIC_ERROR{{@>3.  PROGRAM_ERROR{{@>4.  STORAGE_ERROR{{@>5.  TASKING_ERROR{{{No, TASKING_ERROR is raised only by programs using tasking, which we haven't{yet discussed.{}q[ 446B440Q440]A block construct lets us declare objects in the^executable~region of the{program.  For example, in the following, I and F come into existence where{they're declared, and go out of existence at the following^end~statement:{{@<procedure BLOCK_DEMO is{@?Q : FLOAT;{@<begin{@?Q := 0.0;{@>^declare`{@A^I : INTEGER;`{@A^F : FLOAT;`{@>^begin`{@A^I := 5;`{@A^F := Q;`{@>^end;`{@?Q := Q + 3.0;{@<end BLOCK_DEMO;{{However, the usual use of a block is to localize an exception handler, not to{bring objects into existence in the executable region of a program.  The{declarative part of the block is optional.  For example, let's rewrite{EXCEPTION_DEMO to make use of a block with an exception handler.{}b[ 447B440] with TEXT_IO; use TEXT_IO;{ procedure EXCEPTION_DEMO is{@$package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@$I@%: INTEGER;{@$WRONG : exception;{ begin{@$loop{@&^begin`{@*NEW_LINE(2);  PUT("Type a positive integer. ");  GET(I);  SKIP_LINE;{@*if I <= 0 then{@-raise WRONG;{@*end if;{@*PUT("The square is ... ");{@*PUT(I*I);{@&^exception`{@*when CONSTRAINT_ERROR | NUMERIC_ERROR =>{@-PUT(" ... too big.");{@*when WRONG =>{@-NEW_LINE;  PUT("I said POSITIVE integer!");{@&^end;`{@$end loop;{ end EXCEPTION_DEMO;{}b[ 448B446]Note that in our rewritten program, a block with an exception handler has been{created inside the loop.  Now, if an exception occurs, the handler will be{executed instead of the rest of the^block`, not the rest of the^procedure`.{Thus, the loop will still be executed, and the program will continue to ask{for integers after an exception is handled.{{There are two advantages to confining exception handlers to small blocks.{First, we narrow down the range of statements that might have raised the{exception.  Recall that the handler can't test which line raised the exception,{but it must have been one of the lines in the block.  (If an exception is{raised outside the block, our program provides no handler for it.)  Second,{program execution will continue after the end of the block.{{If an exception occurs for which there's no handler, the exception reaches the{next higher level.  For example, if the block in EXCEPTION_DEMO somehow raises{STORAGE_ERROR and doesn't handle it, an exception handler for the whole{procedure would get a chance to handle it.  (In our case, there is none.)  If{it's still unhandled, it's as if the^call~to EXCEPTION_DEMO raised{STORAGE_ERROR.  If the caller doesn't handle it, the exception reaches the{caller's caller, etc.  If the exception reaches the main program and is still{unhandled, the program is stopped and the system displays the name of the{exception.  However, exceptions that are handled don't even reach the caller.{}b[ 449B447]In the unusual case of an exception raised in the^declarative~region, the unit{raising the exception (subprogram, block, etc.) is^not~given a chance to handle{it.  Exceptions raised in the declarative region immediately reach the next{higher level.{{In a handler, the word^raise~may be used without a name of an exception to{re-raise whatever exception brought control to the handler.  This is especially{useful after^when others =>`, because any one of a number of exceptions might{have transferred control there.  For example,{{@1when others =>{@4PUT_LINE("I don't know what went wrong.");{@4-- Close files and do general cleanup.{@3^raise;`{{This lets us do some processing of the error, and still lets the next higher{level do additional processing.  Note that it's superfluous to say simply^when{others => raise;~because the exception will reach the next higher level even if{that code is omitted.  Any unhandled exception reaches the next higher level.{{An error occurring^in an exception handler~is unhandled and reaches the next{higher level (unless it occurs in a block with its own exception handler).{}b[ 450B448]@*with TEXT_IO; use TEXT_IO;@-separate (ONE){@*procedure ONE is@7procedure TWO is{@-procedure TWO is separate;@-CAIN : exception;{@*begin@Bbegin{@-TWO;@Craise CAIN;{@*exception@>exception{@-when others =>@9when others =>{@0PUT_LINE("1");@9PUT_LINE("2");{@*end ONE;@?end TWO;{{{@6What will the above program display?{{@61.  The program will display 1.{{@62.  The program will display 2.{}Please press 1 or 2, or B to go back.[24511452B449]@*with TEXT_IO; use TEXT_IO;@-separate (ONE){@*procedure ONE is@7procedure TWO is{@-procedure TWO is separate;@-CAIN : exception;{@*begin@Bbegin{@,^TWO;~@A^raise CAIN;`{@*exception@>exception{@-when others =>@8^when others =>`{@0PUT_LINE("1");@8^PUT_LINE("2");`{@*end ONE;@?end TWO;{{{%You're right!~ TWO handles the exception, so it never reaches ONE.{}q[ 453B450Q450]@*with TEXT_IO; use TEXT_IO;@-separate (ONE){@*procedure ONE is@7procedure TWO is{@-procedure TWO is separate;@-CAIN : exception;{@*begin@Bbegin{@-TWO;@Craise CAIN;{@*exception@>exception{@-when others =>@9when others =>{@0PUT_LINE("1");@9PUT_LINE("2");{@*end ONE;@?end TWO;{{{No, TWO handles the exception, so it never reaches ONE.{}q[ 453B450Q450]@?MORE ABOUT TEXT_IO{{We're almost ready for Outside Assignment 5.  For that assignment, we had to{cover type TEXT, access types, and exceptions.  We also need to learn a little{more about TEXT_IO before we do the assignment.{{TEXT_IO is used for input and output to and from text files as well as input{and output to and from the terminal.  Text files are files that can be listed{at the terminal.  (Binary files and random access files are handled with the{packages SEQUENTIAL_IO and DIRECT_IO, which will be discussed in the Advanced{Topics section.){{The full specification of TEXT_IO appears in section 14.3.10 of the LRM.  It's{rather long, and some of the procedures and functions are rarely used.  So{there's a simplified specification of TEXT_IO in your printed course notes,{starting on page 17.  Please consult your printed course notes during the{following discussion.{{Note that there's a limited private type called FILE_TYPE.  For each file that{our program will use, we must create an object of this type, for example,{%F1, F2 : FILE_TYPE;`.  We can then use these objects in the procedures CREATE{and OPEN, to associate file names with the objects of type FILE_TYPE.{}b[ 454B450]Note that the I/O procedures, such as NEW_LINE, PUT, and GET, have one version{for use with the terminal, and another version for use with a file.  The file{version takes an object of type FILE_TYPE,^not~the name of the file.  The file{must first have been CREATEd or OPENed.{{The exception STATUS_ERROR is raised by trying to do I/O on a closed file.{MODE_ERROR is raised by trying to read from a file opened or created with mode{OUT_FILE, or by trying to write to a file of mode IN_FILE.  NAME_ERROR is{raised by trying to OPEN a file that doesn't exist, or by trying to CREATE a{file with a name not allowed by the system.  END_ERROR is raised by trying to{read past an end-of-file.{{NEW_LINE creates one or more blank lines on^output`, and SKIP_LINE skips one or{more lines of^input`.  We can PUT characters and strings, and we can PUT_LINE a{string.  We can GET a character, and GET_LINE a string.  Note that when we{GET_LINE a string, the procedure returns the number of characters that were in{the line.  Thus, if we have^S : STRING(1 .. 80);  LEN : INTEGER;~and we execute{%GET_LINE(S, LEN);~and the user types^Hello~followed by CR, LEN will be set to{5, S(1 .. 5) will be set to "Hello", and the rest of S will be unmodified.{{The generic package INTEGER_IO can be instantiated for any integer type,{including user-defined types and derived types like COUNTER and NO_OF_APPLES.{}b[ 455B453]When we call PUT in our instantiation of INTEGER_IO, we can optionally specify{the width and the base.{{The generic package FLOAT_IO can be instantiated for any floating point type,{such as FLOAT and the user-defined type REAL that we created earlier.  PUT{allows us optionally to specify the number of places before and after the{decimal point, and the size of the optional exponent field.{{The generic package ENUMERATION_IO can be instantiated for any enumeration{type.  PUT allows us optionally to specify the width.{{TEXT_IO contains another generic package FIXED_IO for fixed point types, not{shown in our simplified version.  Fixed point types will be discussed in the{Advanced Topics section.{{To illustrate the use of TEXT_IO, here's a simple program that prompts for the{names of an old input file and a new output file, and copies the input file to{the output.  It's assumed that the input file is an ASCII text file no wider{than 80 characters, and that it contains no special control characters such as{form feeds:{}b[ 456B454]@(^with TEXT_IO; use TEXT_IO;`{@(^procedure FILECOPY is`{@+^F1, F2 : FILE_TYPE;`{@+^S@&: STRING(1 .. 80);`{@+^LEN@$: INTEGER;`{@(^begin`{@+^PUT("Input file: ");  GET_LINE(S, LEN);`{@+^OPEN(FILE => F1, MODE => IN_FILE, NAME => S(1 .. LEN));`{@+^PUT("Output file: ");  GET_LINE(S, LEN);`{@+^CREATE(FILE => F2, MODE => OUT_FILE, NAME => S(1 .. LEN));`{@+^while not END_OF_FILE(F1) loop`{@.^GET_LINE(F1, S, LEN);`{@.^PUT_LINE(F2, S(1 .. LEN));`{@+^end loop;`{@+^CLOSE(F1);`{@+^CLOSE(F2);`{@(^end FILECOPY;`{{In many systems, all files are closed automatically when the main program{terminates, and this program would work even without^CLOSE(F1);~and^CLOSE(F2);`.{{This program also appears on page 19 of your printed course notes.{}b[ 457B455]As this is written (Sept., 1992), there's no way to test whether a file already{exists without trying to OPEN it and trapping the NAME_ERROR if the file{doesn't exist.  There's talk of enhancing TEXT_IO with the next revision (9X){of the Ada standard.{{The following function determines whether a file name represents an existing{file.  It appears on page 19 of your printed course notes:{{@+^with TEXT_IO; use TEXT_IO;`{@+^function EXISTS(FILE_NAME : in STRING) return BOOLEAN is`{@.^F@&: FILE_TYPE;`{@.^ANSWER : BOOLEAN := TRUE;`{@+^begin`{@.^begin`{@1^OPEN(F, IN_FILE, FILE_NAME);`{@1^CLOSE(F);`{@.^exception`{@1^when NAME_ERROR => ANSWER := FALSE;`{@.^end;`{@.^return ANSWER;`{@+^end EXISTS;`{}b[ 458B456]@@1.  STATUS_ERROR{{@@2.  MODE_ERROR{{@@3.  NAME_ERROR{{@@4.  END_ERROR{{{@&Which exception is raised by attempting to do I/O on a closed file?{}Please press 1, 2, 3, or 4, or B to go back.[1459246034614462B457]@?^1.  STATUS_ERROR`{{@@2.  MODE_ERROR{{@@3.  NAME_ERROR{{@@4.  END_ERROR{{{%You're right!~ STATUS_ERROR is raised by an attempt to do I/O on a closed file.{}q[ 463B458Q458]@@1.  STATUS_ERROR{{@@2.  MODE_ERROR{{@@3.  NAME_ERROR{{@@4.  END_ERROR{{{No, MODE_ERROR is raised by an attempt to read from a file of mode OUT_FILE, or{write to a file of mode IN_FILE.{}q[ 463B458Q458]@@1.  STATUS_ERROR{{@@2.  MODE_ERROR{{@@3.  NAME_ERROR{{@@4.  END_ERROR{{{No, NAME_ERROR is raised by an attempt to OPEN a file that doesn't exist, or{CREATE a file with an illegal name.{}q[ 463B458Q458]@@1.  STATUS_ERROR{{@@2.  MODE_ERROR{{@@3.  NAME_ERROR{{@@4.  END_ERROR{{{No, END_ERROR is raised by an attempt to read past an end-of-file.{}q[ 463B458Q458]@.OUTSIDE ASSIGNMENT 5 - WRITING A SIMPLE LINE EDITOR{{We're finally ready for the next Outside Assignment!  This assignment will give{you a chance to write a program of greater complexity than the previous{assignments.  By the time you've completed Outside Assignment 5, you should{feel comfortable with Ada.  The full set of requirements for the line editor we{want you to write are in your printed course notes, starting on page 20.  We'll{discuss them briefly here.  No test driver is supplied, but after you've{written the program, we'll give you some tests to perform manually on your line{editor.  You've completed the assignment when your editor passes all the tests.{{Imagine that your screen editor is unavailable to a particular user, perhaps{because he's dialing your computer from a remote location, and your screen{editor writes directly to the screen.  You want to write a line editor.  While{your computer already has a line editor called EDLIN, it's difficult to learn{to use.  The line editor you'll write, called LEDIT, will take almost no effort{to learn.  The only commands are LIST and EXIT.{{The user begins each line of text with a line number, similar to Basic.  Line{numbers must be integers between 1 and 29999.  Regardless of the order in which{lines are entered, LEDIT maintains a linked list of lines in order by number,{so that it can LIST the text in order, or write it to a file.{}b[ 464B458]Line numbers need not be consecutive, and they may be preceded by any number of{spaces.  For example, if we type{{%40 -- This is a comment.{@#20 begin{10 with TEXT_IO; use TEXT_IO;{@&30 end ADD;`{{and then type^LIST`, the editor displays{{@#10 with TEXT_IO; use TEXT_IO;{@#20 begin{@#30 end ADD;{@#40 -- This is a comment.{{To^insert~lines, we merely type lines with intermediate line numbers.  In our{example, if we now type{{%15 procedure HELLO is{LIST`{{we'll see{}b[ 465B463]@#10 with TEXT_IO; use TEXT_IO;{@#15 procedure HELLO is{@#20 begin{@#30 end ADD;{@#40 -- This is a comment.{{To^replace~a line, we simply retype the line with the same line number as the{line to be replaced, and to^delete~a line, we type only the line number.  If{we now type{{%15 procedure ADD is{40{LIST`{{we'll see{{@#10 with TEXT_IO; use TEXT_IO;{@#15 procedure ADD is{@#20 begin{@#30 end ADD;{}b[ 466B464]Thus the user can insert, replace, and delete lines by line numbers, without{learning any commands!  If the user forgets the space after the line number, no{harm is done; LEDIT takes^20begin~the same as^20 begin`.  However, the user can{indent code by adding^extra~spaces after the line number.  The following{example has three^extra~spaces after each line number (four spaces total):{{%24@$PUT(2 + 2);{26@$NEW_LINE;{18@$package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{LIST`{{@#10 with TEXT_IO; use TEXT_IO;{@#15 procedure ADD is{@#18@$package MY_INT_IO is new INTEGER_IO(INTEGER); use MY_INT_IO;{@#20 begin{@#24@$PUT(2 + 2);{@#26@$NEW_LINE;{@#30 end ADD;{{When LISTing, LEDIT always allows exactly five spaces for the line number, so{that the text lines up correctly:{}b[ 467B465]%LIST`{{@$2 This is a sample listing,{@#20 showing how the text{  200 lines up, even when{ 2000 some line numbers are{20000 longer than others.{{When we type^EXIT`, LEDIT writes the output file^without~the line numbers.  The{text above would all start in column 1 of the output file.{{For LEDIT to be useful with files larger than a page, it must be possible to{list a range of lines:{{%LIST 20 - 30`{{This is only a summary of the requirements for LEDIT.  Please refer to pages{20-24 of your printed course notes for the actual requirements.  As a point of{reference, our solution requires about 180 lines of Ada on four pages.{{Here are the steps to follow for Outside Assignment 5.  They can also be found{in the printed course notes on page 25:{}b[ 468B466]1.  Carefully read the requirements starting on page 20 of the printed course{@$notes.  Take your time.{{2.  Write the Ada code, compile, and link.  Call the main program LEDIT.  If{@$you have any questions about what LEDIT should do, you can compile and run{@$our solution, which is in LEDIT.ANS.{{3.  Refer to pages 26-28 of the printed course notes for instructions on{@$testing your line editor.  If any tests are failed, go back to step 2.{{4.  When all the tests are passed, you've completed the assignment and will{@$have a chance to compare your solution with ours.{{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 5.  It{will probably take several days.  Take your time; there's no deadline.  Good{luck!{}Please type X to exit, a space to go on, or B to go back.[ 469B467]@-^Congratulations on Completing Outside Assignment 5!`{{If you like, you can compare your solution with ours, which is in LEDIT.ANS.  A{listing starts on page 29 of your printed course notes.  Note that a single{procedure handles adding, deleting, and replacing lines.  Replacing is done by{first deleting, then adding a line.{{Your solution might be very different from ours, but if it passed all the{tests, consider it correct.{{Early in this course we used the generic package INTEGER_IO.  Let's now learn{how to write our own generic packages, procedures, and functions.{}b[ 470B468]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@H^>  GENERICS, TASKING, AND ASSIGNMENT 6`{@#Operators, Control Constructs, and{@&Assignment 2@:Advanced Topics{}b[ 471B469]@DGENERICS{{It would be easy to write a package that creates a single stack of 10 INTEGERs,{and lets us PUSH and POP on it.  However, the code would be about the same{regardless of the size of the stack, and regardless of the type of objects on{the stack.  For example, a second package that creates a stack of 50 DATEs{would look about the same.  We can write one^generic~package, and instantiate{it for any size and almost any type we need.  The specification is:{{@4^generic`{@7^SIZE : POSITIVE;`{@7^type DUMMY is private;`{@4^package STACK_PACKAGE is`{@7^procedure PUSH(OBJECT : in DUMMY);`{@7^function POP return DUMMY;`{@4^end STACK_PACKAGE;`{{Since both SIZE and type DUMMY are generic, both must be specified when we{instantiate the package:{{@'^package STACK_OF_10_INTEGERS is new STACK_PACKAGE(10, INTEGER);`{@'^package STACK_OF_50_DATES@$is new STACK_PACKAGE(50, DATE);`{}b[ 472B470]If the generic part says^type DUMMY is private;~then the subprogram or package{body may do only three things with objects of type DUMMY: create them, assign{them, and test them for equality or inequality.  Note that this is similar to{the list of things we may do with a private type^outside~an ordinary package.{In this case, we're listing what we can do^inside~the generic package.  Calling{the package's subprograms isn't on our list, because they're not written yet!{We're listing the things we can do when we write the body of the package.  Of{course, once we write some subprograms, other subprograms can call them.{{Although we can do only three things with objects of a private type inside a{generic package, we can instantiate that package with almost any type at all.{Our STACK_PACKAGE can be instantiated for DATEs, STRINGs (see the next{paragraph), RAINBOW_COLORs, FLOATs, and any type for which we can assign{objects and test them for equality.  That means any type except a limited type.{We can't instantiate STACK_PACKAGE for type TEXT_IO.FILE_TYPE (a limited{private type), or for task types (discussed later), because in our package{we're allowed to assign and test for equality objects of type DUMMY.{{Since we can't create objects of an unconstrained array type, if we want to{instantiate STACK_PACKAGE for STRINGs, we must use a constrained subtype of{STRING.  For example, we could write^subtype NAME is STRING(1 .. 30);~and then{write^package STACK_OF_50_NAMES is new STACK_PACKAGE(50, NAME);`.{}b[ 473B471]We could instantiate our package even for limited types like TEXT_IO.FILE_TYPE{if the generic part had said^type DUMMY is limited private;`.  However, the only{thing our package could do with objects of that type is create them.{Ordinarily, that's not very useful.{{If the generic part says^type DUMMY is ( <> );~then we can instantiate the{package (or subprogram) for any discrete type.  That means any enumeration or{integer type: CHARACTER, BOOLEAN, COUNTER, NO_OF_APPLES, etc.  Inside the{package, attributes like 'FIRST are available.{{If the generic part says^type DUMMY is range <>;~then we can instantiate for{any integer type.  Inside the package, we can do things that can be done with{all integer types, such as add, etc.{{If the generic part says^type DUMMY is delta <>;~then we can instantiate for{any fixed point type, to be discussed in the Advanced Topics section.{{Finally, if the generic part says^type DUMMY is digits <>;~then we can{instantiate for any floating point type, such as FLOAT or the REAL we created.{{The specification of a generic subprogram must be given separately from the{body.  For example, we can't eliminate the highlighted line in this function:{}b[ 474B472]@(generic{@+type DUMMY_FLOAT is digits <>;{@+type DUMMY_VECTOR is array (INTEGER range <>) of DUMMY_FLOAT;{@'^function SUM(V : in DUMMY_VECTOR) return DUMMY_FLOAT;`{@(function SUM(V : in DUMMY_VECTOR) return DUMMY_FLOAT is{@+ANSWER : DUMMY_FLOAT := 0.0;{@(begin{@+for I in V'RANGE loop{@.ANSWER := ANSWER + V(I);{@+end loop;{@+return ANSWER;{@(end SUM;{{We can instantiate SUM and call it as follows:{{@/^type VECTOR is array(INTEGER range <>) of FLOAT;`{@/^V1 : VECTOR(1 .. 10);`{@/^X  : FLOAT;`{@/^function SUMV is new SUM(FLOAT, VECTOR);`{@0...{@/^X := SUMV(V1);`{}b[ 475B473]@)generic{@,type DUMMY is range <>;{@)procedure DISPLAY(ITEM : in DUMMY);{{@)type NO_OF_APPLES is new INTEGER;{@)type COUNTER is range 0 .. 1_000_000;{@)type ANSWER is (YES, NO, MAYBE);{@)procedure DISPLAY_APPLES@#is new DISPLAY(NO_OF_APPLES);  -- 1{@)procedure DISPLAY_COUNTERS is new DISPLAY(COUNTER);@'-- 2{@)procedure DISPLAY_ANSWERS  is new DISPLAY(ANSWER);@(-- 3{{{@)Which commented line in the above program segment is^illegal`?{}Please press 1, 2, or 3, or B to go back.[347614772478B474]@)generic{@,type DUMMY is range <>;{@)procedure DISPLAY(ITEM : in DUMMY);{{@)type NO_OF_APPLES is new INTEGER;{@)type COUNTER is range 0 .. 1_000_000;{@)type ANSWER is (YES, NO, MAYBE);{@)procedure DISPLAY_APPLES@#is new DISPLAY(NO_OF_APPLES);  -- 1{@)procedure DISPLAY_COUNTERS is new DISPLAY(COUNTER);@'-- 2{@(^procedure DISPLAY_ANSWERS  is new DISPLAY(ANSWER);@(-- 3`{{{%You're right!~ When the generic part says^type DUMMY is range <>;`, the{procedure may be instantiated for any integer type.  ANSWER is a discrete type,{but not an integer type.{{In the Advanced Topics section, we'll show an example of a generic function.{}q[ 479B475Q475]@)generic{@,type DUMMY is range <>;{@)procedure DISPLAY(ITEM : in DUMMY);{{@)type NO_OF_APPLES is new INTEGER;{@)type COUNTER is range 0 .. 1_000_000;{@)type ANSWER is (YES, NO, MAYBE);{@)procedure DISPLAY_APPLES@#is new DISPLAY(NO_OF_APPLES);  -- 1{@)procedure DISPLAY_COUNTERS is new DISPLAY(COUNTER);@'-- 2{@)procedure DISPLAY_ANSWERS  is new DISPLAY(ANSWER);@(-- 3{{{No, when the generic part says^type DUMMY is range <>;`, the procedure may be{instantiated for any integer type.  NO_OF_APPLES is a type derived from{INTEGER, so it's an integer type.{}q[ 479B475Q475]@)generic{@,type DUMMY is range <>;{@)procedure DISPLAY(ITEM : in DUMMY);{{@)type NO_OF_APPLES is new INTEGER;{@)type COUNTER is range 0 .. 1_000_000;{@)type ANSWER is (YES, NO, MAYBE);{@)procedure DISPLAY_APPLES@#is new DISPLAY(NO_OF_APPLES);  -- 1{@)procedure DISPLAY_COUNTERS is new DISPLAY(COUNTER);@'-- 2{@)procedure DISPLAY_ANSWERS  is new DISPLAY(ANSWER);@(-- 3{{{No, when the generic part says^type DUMMY is range <>;`, the procedure may be{instantiated for any integer type.  The definition of the user-defined type{COUNTER has the word^range`, so COUNTER is an integer type.{}q[ 479B475Q475]@DTASKING{{Here are two versions of a program with two parallel tasks.  Since the main{program is a task, these two versions are equivalent.{{@)with TEXT_IO; use TEXT_IO;@)with TEXT_IO; use TEXT_IO;{@)procedure TASK_DEMO is@0procedure TASK_DEMO is{@+^task A;~@:^task A;`{@+^task body A is~@3^task body A is`{@+^begin~@<^begin`{@.^PUT_LINE("b");~@3^PUT_LINE("a");`{@.^PUT_LINE("b");~@3^PUT_LINE("a");`{@+^end A;~@;^end A;`{@)begin@@^task B;`{@+^PUT_LINE("a");~@3^task body B is`{@+^PUT_LINE("a");~@3^begin`{@)end TASK_DEMO;@:^PUT_LINE("b");`{@Q^PUT_LINE("b");`{@N^end B;`{@Lbegin{@Onull;{@Lend TASK_DEMO;{}b[ 480B475]Our program could have specified as many tasks as we like.  Also, our tasks{could have declarations between^task body ... is~and^begin`.  If the computer{has several processors, and the Ada compiler makes use of that fact, the tasks{could actually run simultaneously.  Otherwise, the compiler may (but doesn't{have to) write code to^time slice~among the tasks, making them^appear~to run{simultaneously.  One implementation of Ada we tried time slices, and the output{of the program looked something like this:{{ab{{ab{{{This happened because PUT_LINE is equivalent to PUT plus NEW_LINE, and thus{PUT_LINE can get interrupted before the CR-LF is output.  Here one task{displayed "a", the other task displayed "b", and then both tasks sent CR-LF.{{Another implementation of Ada we tried won't time-slice unless told to with a{%pragma`, covered in the Advanced Topics section.  So the output of the same{program with that implementation of Ada looked like this:{}b[ 481B479]a{a{b{b{{In this case one task ran to completion before the other task started.  The{point is that both implementations of Ada ran our program correctly, but with{different results.{{When data is passed between tasks, we often don't want the process interrupted.{For example, suppose one task updates a record with several fields, such as a{DATE.  Another task reads the record.  We don't want the second task to{interrupt the first in the middle of updating a record.  Otherwise, the second{task might read an updated DAY field, an updated MONTH field, and an old YEAR{field, which would be meaningless.  Ada has an elegant solution to this{problem, called the^rendezvous`.{{In this example, we assume that the main program created both procedure CALLER{and task SERVER, and defined type DATE:{}b[ 482B480]@&procedure CALLER is@*task SERVER is{@)D : DATE;@4entry UPDATE(ITEM : in out DATE);{@Cend SERVER;{@&begin@8task body SERVER is{@(^-----;~@3begin{@(^-----;  -- Block 1~@)^-----;  -- Block 3`{@(^-----;~@5^-----;`{@E^accept UPDATE(ITEM : in out DATE) do`{@(^SERVER.UPDATE(D);~@-^-----;  -- Block 4`{@H^-----;`{@(^-----;~@5^end UPDATE;`{@(^-----;  -- Block 2~@)^-----;  -- Block 5`{@(^-----;~@5^-----;`{@&end CALLER;@2end SERVER;{{Code blocks 1 and 3 run in parallel (perhaps simultaneously, as discussed).{Then CALLER waits at the call to SERVER.UPDATE while SERVER executes block 4.{Block 4 is called the critical section of code, where records might be updated,{etc.  When this^rendezvous~is over, blocks 2 and 5 run in parallel.  If CALLER{reaches the call before SERVER reaches^accept`, CALLER will wait patiently{there for SERVER.  If SERVER reaches^accept~first, it will wait patiently there{for a caller.{}b[ 483B481]@&procedure CALLER is@*task SERVER is{@)D : DATE;@3^entry~UPDATE(ITEM : in out DATE);{@Cend SERVER;{@&begin@8task body SERVER is{@)-----;@4begin{@)-----;  -- Block 1@+-----;  -- Block 3{@)-----;@7-----;{@E^accept~UPDATE(ITEM : in out DATE)^do`{@(^SERVER.UPDATE(D);~@.-----;  -- Block 4{@I-----;{@)-----;@7end UPDATE;{@)-----;  -- Block 2@+-----;  -- Block 5{@)-----;@7-----;{@&end CALLER;@2end SERVER;{{The call to UPDATE looks like a procedure call.  We can't^use~a task, so the{call requires dot notation.  The^entry~specification looks like a procedure{specification, with^entry~replacing^procedure`.  The task specification may have{any number of^entry~statements; if it has none, we write simply^task SERVER;`.{The^accept~block looks like a procedure without declarations, but^accept`{replaces^procedure`, and^do~replaces^is begin`.  An^accept~with no parameters{and no statements may be written simply as^accept UPDATE;`.{}b[ 484B482]@-procedure MASTER is@.task SLAVE is{@Qentry SYNC;{@Nend SLAVE;{@Ntask body SLAVE is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;-----;{@0SLAVE.SYNC;@6accept SYNC;{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;-----;{@-end MASTER;@6end SLAVE;{{{True or False?  Statements in blocks 1 and 4 could execute simultaneously.{}Please press T for true or F for false, or B to go back.[F485T486B483]@-procedure MASTER is@.task SLAVE is{@Qentry SYNC;{@Nend SLAVE;{@Ntask body SLAVE is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;-----;{@/^SLAVE.SYNC;~@4^accept SYNC;`{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;-----;{@-end MASTER;@6end SLAVE;{{{%You're right!~ MASTER will wait patiently at^SLAVE.SYNC~for SLAVE to reach{%accept`, or SLAVE will wait patiently at^accept~for MASTER to reach{%SLAVE.SYNC;`.  Therefore, blocks 1 and 4 can't execute simultaneously.{}q[ 487B484Q484]@-procedure MASTER is@.task SLAVE is{@Qentry SYNC;{@Nend SLAVE;{@Ntask body SLAVE is{@-begin@<begin{@0-----;@;-----;{@0-----;  -- Block 1@/-----;  -- Block 3{@0-----;@;-----;{@0SLAVE.SYNC;@6accept SYNC;{@0-----;@;-----;{@0-----;  -- Block 2@/-----;  -- Block 4{@0-----;@;-----;{@-end MASTER;@6end SLAVE;{{{False.  MASTER will wait patiently at^SLAVE.SYNC~for SLAVE to reach^accept`, or{SLAVE will wait patiently at^accept~for MASTER to reach^SLAVE.SYNC;`.{Therefore, blocks 1 and 4 can't execute simultaneously.{}q[ 487B484Q484]If several tasks call an entry before the server reaches^accept`, the calls are{queued first-in, first-out.{{We can write a^select~block to accept any of several different calls:{{@8^select`{@<accept A;{@8^or`{@<accept B(I : in INTEGER) do{@?-----;{@<end B;{@8^or`{@<accept C;{@8^end select;`{{When^select~is reached, the task waits for a call to A or B or C.  If calls to{more than one entry are pending, one will be chosen arbitrarily.{{A^delay~statement, used in ordinary code, will delay a specified number of{seconds (plus any system overhead).  For example,{}b[ 488B484]@CA;{@B^delay 5.0;`{@CB;{{will call A, delay five seconds (plus system overhead), and then call B.{However, when used in a^select~block, the meaning is a bit different.  It's{used to implement an^impatient server`.  For example,{{@@^select`{@Daccept A;{@@^or`{@Daccept B;{@@^or`{@C^delay 5.0;`{@DC;{@@^end select;`{{will wait up to five seconds for a call to A or B.  If no call is received, C{will be called.{{%Guards~can be used to switch alternatives of a^select~block on and off.  For{example,{}b[ 489B487]@@J : INTEGER;{@@...{@?^select`{@B^when J = 1 =>`{@Caccept A;{@?^or`{@B^when J = 2 =>`{@Caccept B;{@?^end select;`{{Here A is an alternative only if the condition (J = 1) is true; B is an{alternative only if J = 2.  If J /= 1, then no call to A will be accepted, even{if one is pending.  If every branch of a^select~block has a guard and all{guards are false, PROGRAM_ERROR is raised.{{Tasks "die" in three ways.  The least elegant way is for a task to^abort~it,{e.g.,^abort SERVER;`.  This is drastic, because SERVER might be doing anything.{A better way is for a family of tasks each to include^terminate;~as one{alternative in a^select~block.  (A "family" of tasks is the set of tasks{created by one "parent," for example, the main program.)  When calls to the{entries in the tasks all cease, all tasks in the family will reach the{%terminate~alternative, and all will die together.{}b[ 490B488]But the most orderly way for a task to die is for it simply to reach its last{statement.  For example, task T below will continue to accept calls to T.A and{T.B until a task calls T.SHUTDOWN.  At that time, T will die.{{@+task T is@6task body T is{@.entry A;@6^DONE : BOOLEAN := FALSE;`{@.entry B;@4begin{@-^entry SHUTDOWN;~@.^while not DONE loop`{@+end T;@>^select`{@Saccept A do{@V-----;{@Send A;{@O^or`{@Saccept B do{@V-----;{@Send B;{@O^or`{@R^accept SHUTDOWN;`{@R^DONE := TRUE;`{@O^end select;`{@L^end loop;`{@Jend T;{}b[ 491B489]Trying to call an entry of a task that has died will raise TASKING_ERROR.{Also, a task can't terminate until all the tasks it creates terminate.  In{particular, the main program can't return to the operating system until all{tasks in the program have died.  Programmers must be careful to avoid possible{deadlocks.  Ada solves many problems that plague other languages, but{unfortunately the deadlock problem remains unsolved.{{A^select~block may have an^else~alternative.  Here's an example of a very{impatient server.  If a call to A or B is pending it will be served, otherwise,{C will be called:{{@@^select`{@Daccept A do{@G-----;{@Dend A;{@@^or`{@Daccept B do{@G-----;{@Dend B;{@@^else`{@DC;{@@^end select;`{}b[ 492B490]type DATE is ...@5task body DATA_PROTECTOR is{task DATA_PROTECTOR is@2SAVE_D : DATE;{@#entry READ_DATE(D : out DATE);@'DONE@#: BOOLEAN := FALSE;{@#entry WRITE_DATE(D : in DATE);@$begin{@#entry SHUTDOWN;@6accept WRITE_DATE(D : in DATE) do{end DATA_PROTECTOR;@8SAVE_D := D:{@Hend WRITE_DATE;{@Hwhile not DONE loop{@Kselect{@Naccept READ_DATE(D : out DATE) do{@QD := SAVE_D;{@Nend READ_DATE;{@Kor{@Naccept WRITE_DATE(D : in DATE) do{@QSAVE_D := D;{True or False?  This task must@0end WRITE_DATE;{serve at least one call to@1or{WRITE_DATE before it will@5accept SHUTDOWN;{accept calls to READ_DATE.@4DONE := TRUE;{@Kend select;{@Hend loop;{@Eend DATA_PROTECTOR;{}Please press T for true or F for false, or B to go back.[T493F494B491]type DATE is ...@5task body DATA_PROTECTOR is{task DATA_PROTECTOR is@2SAVE_D : DATE;{@#entry READ_DATE(D : out DATE);@'DONE@#: BOOLEAN := FALSE;{@#entry WRITE_DATE(D : in DATE);@$begin{@#entry SHUTDOWN;@5^accept WRITE_DATE(D : in DATE) do`{end DATA_PROTECTOR;@7^SAVE_D := D:`{@G^end WRITE_DATE;`{@Hwhile not DONE loop{@Kselect{@M^accept READ_DATE(D : out DATE) do`{@P^D := SAVE_D;`{@M^end READ_DATE;`{@Kor{@M^accept WRITE_DATE(D : in DATE) do`{@P^SAVE_D := D;`{%You're right!~ The extra^accept~@-^end WRITE_DATE;`{block outside the loop forces us@+or{to call WRITE_DATE at least once@.accept SHUTDOWN;{before we can call READ_DATE.@1DONE := TRUE;{@Kend select;{@Hend loop;{@Eend DATA_PROTECTOR;{}q[ 495B492Q492]type DATE is ...@5task body DATA_PROTECTOR is{task DATA_PROTECTOR is@2SAVE_D : DATE;{@#entry READ_DATE(D : out DATE);@'DONE@#: BOOLEAN := FALSE;{@#entry WRITE_DATE(D : in DATE);@$begin{@#entry SHUTDOWN;@6accept WRITE_DATE(D : in DATE) do{end DATA_PROTECTOR;@8SAVE_D := D:{@Hend WRITE_DATE;{@Hwhile not DONE loop{@Kselect{@Naccept READ_DATE(D : out DATE) do{@QD := SAVE_D;{@Nend READ_DATE;{@Kor{@Naccept WRITE_DATE(D : in DATE) do{@QSAVE_D := D;{True.  The extra^accept~block@1end WRITE_DATE;{outside the loop forces us to@.or{call WRITE_DATE at least once@1accept SHUTDOWN;{before we can call READ_DATE.@1DONE := TRUE;{@Kend select;{@Hend loop;{@Eend DATA_PROTECTOR;{}q[ 495B492Q492]The^select~block can be used in a caller as well as a server.  The following{block waits up to five seconds to call entry A in task T.  If T isn't ready to{accept the call in five seconds, the block calls procedure B instead.  This is{called an impatient customer:{{@@^select`{@C^T.A;`{@@^or`{@C^delay 5.0;`{@C^B;`{@@^end select;`{{A very impatient customer can be implemented with^else`.  This block calls T.A{only if T is ready to accept the call immediately, otherwise, it calls B.{{@A^select`{@D^T.A;`{@A^else`{@D^B;`{@A^end select;`{}b[ 496B492]Task^types~may be declared.  This permits us to create an array of tasks, and{it lets us bring tasks into existence via access types.  Tasks begin executing{as soon as they're brought into existence.  For example,{{@;^task type X is`{@>^entry E;`{@;^end X;`{@;^type P is access X;`{@;^X1 : P;`{@;^A : array(1 .. 10) of X;`{@;^task body X is`{@?...{@;^end X;`{{Entries to these tasks are called thus:{{@;^A(5).E;`{@;^X1 := new X;`{@;^X1.all.E;~or just^X1.E;`{}b[ 497B495]Ada comes with a package CALENDAR; the specification is in section 9.6 of the{LRM.  The part that concerns us here is shown below.  Type DURATION is a fixed{point type built into Ada; the^delay~statement discussed earlier takes an{object of type DURATION.{{@'^package CALENDAR is`{@*^type TIME is private;`{@*^function CLOCK return TIME;`{@*^function "+"(LEFT : TIME; RIGHT : DURATION) return TIME;`{@*^function "-"(LEFT : TIME; RIGHT : TIME)@%return DURATION;`{@+...{@'^end CALENDAR;`{{Not shown are a few other operators, and subprograms to convert between type{TIME and the year, month, day, and number of seconds since midnight.{{Let's write a program segment, using CALENDAR, that calls A every five seconds:{}b[ 498B496]@6^with CALENDAR; use CALENDAR;`{@7...{@6^NEXT_EVENT : TIME := CLOCK + 5.0;`{@7...{@6^loop`{@9^delay NEXT_EVENT - CLOCK;`{@9^A;`{@9^NEXT_EVENT := NEXT_EVENT + 5.0;`{@6^end loop;`{{Note that this loop accounts for the time required to call A.  Instead of{delaying 5.0, we calculate the time of the next call in NEXT_EVENT, and delay{that time minus the current time, which we obtain by calling CLOCK.  Thus the{program will go through the loop once every 5.0 seconds, even if it takes a{little time to call A.{{The^-~and^+~operators in this program segment all use infix functions from{CALENDAR.{{We're now ready for Outside Assignment 6!  It will be much simpler than Outside{Assignment 5.{}b[ 499B497]@3OUTSIDE ASSIGNMENT 6 - EXERCISE IN TASKING{{On page 33 of your printed course notes is a listing of^TASKING.DUM`.  This{program calls a task entry to display^Tick!~on the screen every five seconds{until it has been displayed nine times.{{Every time^delay~is executed, the message^(5-second delay)~is displayed so that{the delay will be visible on the screen.  The program is entirely in lower{case, because your assignment is to modify it.  If you make your modifications{in upper case, it will be easy to see what you have changed.{{We want you to change the declaration of T from a single task to an^array~of{three tasks.  The tasks are numbered 1, 2, and 3.  Task 1 is to be activated{every^two~five-second intervals.  Task 2 is to be activated every^three~five-{-second intervals, and task 3, every^four`.  Also, instead of displaying^Tick!`,{each task will identify itself by number, for example,^Task number 3 is{starting`.  Output should look as shown on page 35 of your printed notes.{}b[ 500B498]We recommend that you create an array of three counters.  Each counter counts{down from its period (2, 3, or 4) to zero by one count every interval.  When a{counter reaches zero, the corresponding task entry is called, and the counter{is reset to its period.  All three counters should be initialized to zero, so{that all three tasks display their messages immediately upon activation of the{program.  You should use the rendezvous mechanism to inform each task of its{number (1, 2, or 3).  Your program should use a loop to do an orderly shutdown{of all three tasks at the end.{{Here are the steps to follow for Outside Assignment 6.  They're also in your{printed course notes on page 34:{}b[ 501B499]1.  Make a copy of TASKING.DUM by typing^COPY TASKING.DUM TASKING.ADA`.{@$Compile, link, and execute the program to make sure it displays^Tick!~nine{@$times, with a 5-second delay after each "Tick."{{2.  Edit TASKING.ADA to become your solution.  Make your changes in upper case.{{3.  Compile TASKING.ADA, link, and execute.{{4.  Compare your output with page 35 of the printed course notes.  If there are{@$any errors, go back to step 2.{{5.  When your output agrees with the printed course notes, you've finished the{@$assignment and will have a chance to compare your solution with ours.{{{Please type X to exit^ADA-TUTR~temporarily, and try Outside Assignment 6.  Work{at your own pace; there's no deadline.  Good luck!{}Please type X to exit, a space to go on, or B to go back.[ 502B500]@-^Congratulations on Completing Outside Assignment 6!`{{If you like, you can compare your solution with ours, which is in TASKING.ANS.{A listing is on page 36 of your printed course notes.  Your solution might be{different from ours, but if your^output~agrees with page 35 of the printed{notes, your solution is correct.{{You've learned a great deal of Ada!  Let's go on to discuss some advanced{topics.{}b[ 503B501]@;^ADA-TUTR COURSE OUTLINE`{{{@#Introduction@=Records, Arrays, and Assignment 3{{@#The Format of an Ada Program@-Recursion and Assignment 4{{@#Generic Instantiation and@0Subprograms and Packages{@&Assignment 1{@LAdditional Types, Exceptions,{@#Simple Declarations and Simple@.TEXT_IO, and Assignment 5{@&Attributes{@LGenerics, Tasking, and Assignment 6{@#Operators, Control Constructs, and{@&Assignment 2@6^>  ADVANCED TOPICS`{}b[ 504B502]@DRENAMING{{A subprogram can be renamed in Ada.  This allows us to avoid the dot notation{without a^use~clause.  For example, if our program^with`s TEXT_IO, we can write:{{@(^procedure PRINT(OBJECT : in STRING) renames TEXT_IO.PUT_LINE;`{{We can now call PRINT instead of TEXT_IO.PUT_LINE.  The old name is still{available.  Note that renaming can change the names of the formal parameters{("dummy arguments").  Renaming can also add, delete, or change default values.{When used in a package, a renaming declaration like the above goes in the{%specification`, not the body.{{We can also rename task entries as procedures.  This is the only way to avoid{the dot notation when calling a task entry.{{A function can be renamed as an infix operator, if it has the right number and{types of parameters.  Also, an infix operator can be renamed as a function.{For example, earlier we defined type VECTOR and wrote:{}b[ 505B503]@-^function "*"(LEFT, RIGHT : in VECTOR) return FLOAT;`{{This could be renamed as follows:{{@'^function DOT_PRODUCT(X, Y : in VECTOR) return FLOAT renames "*";`{{Renaming can get around the restriction that library subprograms can't be infix{operators.  We can use a normal function name for the library, and rename it as{an infix operator for our program.  Similarly, we can get around the rule that{library subprograms can't overload each other.  We can give subprograms{distinct names in the library, and rename them in our program to overload each{other.{{An attribute that takes a parameter, such as^PRED~and^SUCC`, can be renamed as a{function.  Record components can be renamed.  If^D~is of the type^DATE~we had{earlier, we can write^J : INTEGER renames D.YEAR;`.  Exceptions can also be{renamed, as in^NO_SUCH_FILE : exception renames TEXT_IO.NAME_ERROR;`.{{A subtype can be used to achieve the effect of renaming a type, for example,{%subtype FILE is TEXT_IO.FILE_TYPE;`.{}b[ 506B504]@:PACKAGES STANDARD AND ASCII{{Ada comes with a package STANDARD.  However, unlike all the other packages,{STANDARD is needed by^every~Ada compilation unit.  Therefore, STANDARD is{automatically^with`ed and^use`d in every compilation.  It need not be mentioned{in a context clause.  STANDARD contains the definitions built into the Ada{language, such as^type BOOLEAN is (FALSE, TRUE);`.  A listing of the package{specification is in Appendix C of the LRM.  Thus, the full name for the type{BOOLEAN is STANDARD.BOOLEAN, the full name for INTEGER is STANDARD.INTEGER,{etc.  Naturally, this normally need not concern the programmer.  The dot{notation is automatic because STANDARD is automatically^use`d in every{compilation.{{However, inside package STANDARD is a package ASCII.  Since this package is{part of STANDARD, we never have to write a^with~clause for it.  But ASCII isn't{automatically^use`d.  If we want the dot notation for ASCII to be automatic, we{have to provide a^use~clause.  As the listing in the LRM shows, ASCII contains{names for all the unprintable ASCII characters, such as BEL, ESC, etc.  It also{provides names for many punctuation marks, in case your terminal or printer{doesn't have them.  For example, DOLLAR, AT_SIGN, etc.  Finally, it provides{names for all lower case letters, from LC_A to LC_Z.{}b[ 507B505]For example, either of the following programs will display^a$b~and ring the{bell or beep the terminal:{{@'with TEXT_IO; use TEXT_IO;{@'procedure AB is{@'begin{@*PUT_LINE(%ASCII.LC_A & ASCII.DOLLAR & ASCII.LC_B & ASCII.BEL`);{@'end AB;{{@'with TEXT_IO; use TEXT_IO;{@'procedure AB is{@)^use ASCII;`{@'begin{@*PUT_LINE(%LC_A & DOLLAR & LC_B & BEL`);{@'end AB;{{Note the placement of^use ASCII;~in the second example.  It's similar to the{placement of^use MY_INT_IO;~in ADD.ADA, which we discussed early in the course.{}b[ 508B506]@8AN ALTERNATIVE TO INFIX NOTATION{{Earlier we learned to define and use infix operators like{{@.type VECTOR is array(INTEGER range <>) of FLOAT;{@-^function "*"(LEFT, RIGHT : in VECTOR) return FLOAT;`{@.A, B : VECTOR(1 .. 10);{@.F@$: FLOAT;{@....{@-^F := A * B;`{{An alternative notation equivalent to^F := A * B;~is^F := "*"(A, B);`.  Why{would anyone want to use this clumsier notation?  If our function is in a{package MATH that the calling program^with`s but for some reason doesn't^use`, we{could use dot notation and write^F := MATH."*"(A, B);`.  But we couldn't use dot{notation directly with infix operators, as in F := A MATH.* B; or even{F := A MATH."*" B;.  Both of those are illegal.  The alternative notation can{also be used to emphasize that an operator comes from package STANDARD.  For{example, if I, J, and K are INTEGERs, we could write^I := STANDARD."*"(J, K);`,{which is equivalent to^I := J * K;`.{}b[ 509B507]Assuming X, Y, and Z have been declared FLOAT, which one of the following is{%illegal`?{{@:1.  X := Y / Z;{{@:2.  X := Y STANDARD."/" Z;{{@:3.  X := STANDARD."/"(Y, Z);{}Please press 1, 2, or 3, or B to go back.[251015113512B508]@:1.  X := Y / Z;{{@9^2.  X := Y STANDARD."/" Z;`{{@:3.  X := STANDARD."/"(Y, Z);{{{%You're right!~ The syntax of number 2 is illegal.  To specify the package{STANDARD, we have to use the syntax of number 3.  Normally, of course, the{syntax of number 1 is used.{}q[ 513B509Q509]@:1.  X := Y / Z;{{@:2.  X := Y STANDARD."/" Z;{{@:3.  X := STANDARD."/"(Y, Z);{{{No, number 1 is the syntax that would ordinarily be used for division, and is{legal.{}q[ 513B509Q509]@:1.  X := Y / Z;{{@:2.  X := Y STANDARD."/" Z;{{@:3.  X := STANDARD."/"(Y, Z);{{{No, number 3 is the correct way to specify package STANDARD explicitly.{}q[ 513B509Q509]@4RECORD DISCRIMINANTS AND RECORD VARIANTS{{The definition of a record type can have^discriminants`, which have the same{form as formal parameters ("dummy arguments") of subprograms, except that the{mode is omitted.  Default values may be supplied.  For example,{{@'type MATRIX is array(INTEGER range <>, INTEGER range <>) of FLOAT;{@'type SQUARE_MATRIX%(SIZE : POSITIVE := 9)~is{@*record{@-SQ : MATRIX%(1 .. SIZE, 1 .. SIZE)`;{@*end record;{{Although objects of type MATRIX can be rectangular, objects of type{SQUARE_MATRIX must be square.  In declaring these objects, we use the same{syntax as a subprogram call, with either positional or named notation:{{@#^A : SQUARE_MATRIX(7);  -- a 7-by-7 matrix`{@#^B : SQUARE_MATRIX(SIZE => 5);  -- a 5-by-5 matrix`{@#^C : SQUARE_MATRIX;  -- a 9-by-9 matrix, using the default value of SIZE`{}b[ 514B509]Of course, subtypes of discriminated records can be declared.  For example,{{@/^subtype CHESS_BOARD is SQUARE_MATRIX(SIZE => 8);`{{A record discriminant is used in the definition of type TEXT in the{TEXT_HANDLER package specification of section 7.6 of the LRM:{{@2MAXIMUM : constant := ... ;{@2subtype INDEX is INTEGER range 0 .. MAXIMUM;{@2...{@1^type TEXT(MAXIMUM_LENGTH : INDEX) is`{@4^record`{@7^POS@#: INDEX := 0;`{@7^VALUE : STRING(1 .. MAXIMUM_LENGTH);`{@4^end record;`{{With the simplified version of type TEXT presented earlier, every object of{type TEXT occupied enough memory for the longest string we expected to handle{(e.g., 80 characters).  With this version, each object of type TEXT that we{create can have just the MAXIMUM_LENGTH we need, and its effective length POS{can vary from zero to that MAXIMUM_LENGTH.  The record discriminant complicates{the package specification only very slightly; see section 7.6 of the LRM.{}b[ 515B513]The definition of a record type can have a^variant`, which also has the same{form as a subprogram formal parameter without the mode.  However, the syntax of{a^case~construct is used to specify part of the record.  Although a record can{have several discriminants, it can have only one variant, and the variant part{must appear last in the record.  For example,{{@8type SEX_TYPE is (MALE, FEMALE);{@8type PERSON%(SEX : SEX_TYPE)~is{@;record{@>AGE : NATURAL;{@=^case SEX is`{@@^when MALE =>`{@C^BEARDED  : BOOLEAN;`{@@^when FEMALE =>`{@C^CHILDREN : NATURAL;`{@=^end case;`{@;end record;{{If the sex of the person is MALE, we want the record to include a BOOLEAN{showing whether he's bearded, but if the sex is FEMALE, we want the record to{include an INTEGER (subtype NATURAL), showing the number of children she has.{}b[ 516B514]@8type SEX_TYPE is (MALE, FEMALE);{@8type PERSON(SEX : SEX_TYPE) is{@;record{@>AGE : NATURAL;{@>case SEX is{@Awhen MALE =>{@DBEARDED  : BOOLEAN;{@Awhen FEMALE =>{@DCHILDREN : NATURAL;{@>end case;{@;end record;{{Objects are declared and given values as we'd expect:{{  ^JOHN : PERSON(SEX => MALE) := (SEX => MALE, AGE => 21, BEARDED => FALSE);`{  ^MARY : PERSON(SEX => FEMALE) := (SEX => FEMALE, AGE => 18, CHILDREN => 0);`{{Attempting to reference JOHN.CHILDREN or MARY.BEARDED will raise{CONSTRAINT_ERROR.  Subtypes may be declared as follows:{{@7^subtype MAN is PERSON(MALE);`{@7^subtype WOMAN is PERSON(FEMALE);`{}b[ 517B515]type COMPUTER_SIZE is (HANDHELD,LAPTOP,PORTABLE,DESKTOP,MAINFRAME,CLUSTER);{type COMPUTER(SIZE : COMPUTER_SIZE) is{@#record{@&K_MEM : POSITIVE;{@&DISKS : NATURAL;{@&case SIZE is{@)when CLUSTER =>{@,NUMBER_OF_UNITS : POSITIVE;{@,DATA_RATE@': FLOAT;{@)when others =>{@,null;{@&end case;{@#end record;{MY_PC@': COMPUTER(DESKTOP) := (DESKTOP, K_MEM => 640, DISKS => 2);@#^-- 1`{COMPANY_LAN : COMPUTER(CLUSTER) := (CLUSTER, K_MEM => 24576, DISKS => 8); ^-- 2`{{Which commented declaration in the above program is^illegal`?{}Please press 1 or 2, or B to go back.[25181519B516]type COMPUTER_SIZE is (HANDHELD,LAPTOP,PORTABLE,DESKTOP,MAINFRAME,CLUSTER);{type COMPUTER(SIZE : COMPUTER_SIZE) is{@#record{@&K_MEM : POSITIVE;{@&DISKS : NATURAL;{@&case SIZE is{@)when CLUSTER =>{@,NUMBER_OF_UNITS : POSITIVE;{@,DATA_RATE@': FLOAT;{@)when others =>{@,null;{@&end case;{@#end record;{MY_PC@': COMPUTER(DESKTOP) := (DESKTOP, K_MEM => 640, DISKS => 2);@$-- 1{%COMPANY_LAN : COMPUTER(CLUSTER) := (CLUSTER, K_MEM => 24576, DISKS => 8);  -- 2`{{%You're right!~ The initialization of COMPANY_LAN fails to include fields for{NUMBER_OF_UNITS and DATA_RATE.{}q[ 520B517Q517]type COMPUTER_SIZE is (HANDHELD,LAPTOP,PORTABLE,DESKTOP,MAINFRAME,CLUSTER);{type COMPUTER(SIZE : COMPUTER_SIZE) is{@#record{@&K_MEM : POSITIVE;{@&DISKS : NATURAL;{@&case SIZE is{@)when CLUSTER =>{@,NUMBER_OF_UNITS : POSITIVE;{@,DATA_RATE@': FLOAT;{@)when others =>{@,null;{@&end case;{@#end record;{MY_PC@': COMPUTER(DESKTOP) := (DESKTOP, K_MEM => 640, DISKS => 2);@$-- 1{COMPANY_LAN : COMPUTER(CLUSTER) := (CLUSTER, K_MEM => 24576, DISKS => 8);  -- 2{{No, the declaration of MY_PC and its initialization are correct.  When SIZE is{DESKTOP, the^others~clause of the^case~applies, so there are no NUMBER_OF_UNITS{and DATA_RATE fields in this case.{}q[ 520B517Q517]@8FIXED POINT AND UNIVERSAL TYPES{{The only fixed point type defined in package STANDARD is DURATION.  However,{Ada lets us define our own fixed point types.  We specify the accuracy with the{reserved word^delta`, and a range constraint is required.  For example,{{@/^type VOLTAGE is delta 0.01 range -20.0 .. 20.0;`{{This guarantees that the objects of type VOLTAGE will be represented with at{least an accuracy of 1/100.  Since the computer is binary, Ada will choose an{internal representation at least as accurate as 1/128.  It might use even{greater accuracy, for example, 1/256.  In any event, it's guaranteed that the{accuracy is at least as good as that requested.{{It's possible to make a request that a particular implementation of Ada can't{handle.  For example, if we write{{@.^type VOLTAGE is delta 1.0E-10 range 0.0 .. 1.0E9;`{{the Ada compiler that we're using may have to report that it has no internal{representation that satisfies this requirement.  (Almost any^delta~would be{unreasonable if Ada didn't require range constraints on all fixed point types.){}b[ 521B517]@0type VOLTAGE is delta 0.01 range -20.0 .. 20.0;{{The set of numbers that can be represented exactly by any Ada that accepts a{type definition like the above is called the^model numbers~of that type.  This{applies to floating types as well as fixed, for example,{{@4^type W is digits 5 range 0.0 .. 100.0;`{{A particular implementation may represent additional numbers exactly; these are{called^safe numbers`.  The safe numbers are a superset of the model numbers;{their range usually is a little larger.{{We can add and subtract objects of a fixed point type.  However, if we multiply{or divide them, we must immediately convert the result to the same or another{numeric type before we can store it.  For example,{{@6^V1, V2, V3 : VOLTAGE;`{@7...{@6^V1 := V2 + V3;  -- legal`{@6^V1 := V2 * V3;  -- illegal`{@6^V1 := VOLTAGE(V2 * V3);  -- legal`{}b[ 522B520]TEXT_IO contains a generic package FIXED_IO for I/O of fixed point types.{{When we declare a variable in Ada, we give its type.  But when we declare a{constant, we may or may not give its type.  For example,{{@3^L  : constant INTEGER := 30;`{@3^M  : constant := 1000;`{@3^E  : constant FLOAT := 2.718281828;`{@3^PI : constant := 3.141592654;`{{Also, when we write a number, such as 3.0 or 29_999, we usually don't qualify{it with a type (for example,^FLOAT'(3.0)`).{{Suppose an implementation of Ada provides types INTEGER, LONG_INTEGER, FLOAT,{and LONG_FLOAT.  How can Ada determine the types of M, PI, 3.0, and 29_999?  M{and 29_999 are said to be of type^universal_integer`; they can assume any{integer type as required.  PI and 3.0 are said to be of type^universal_real~and{can assume any floating or fixed point type as required.{{We can't explicitly declare objects to be of universal types.  However, we can{write{}b[ 523B521]@9M  : constant := 1000;{@9PI : constant := 3.141592654;{@8^I  : INTEGER;`{@8^LI : LONG_INTEGER;`{@8^F  : FLOAT;`{@8^LF : LONG_FLOAT;`{@9...{@8^I := M;  LI := M;`{@8^I := 29_999;  LI := 29_999;`{@8^F := PI;  LF := PI;`{@8^F := 3.0;  LF := 3.0;`{{and in each case the constant assumes the correct type.  The result of{multiplying or dividing two numbers of a fixed point type is said to be of type{%universal_fixed`.  This result must be explicitly converted to some numeric{type before it can be stored.{{Most of the attributes that produce integer results, like^POS`, are of type{universal_integer.  For example, with the declarations above, we could write{{@:^I  := CHARACTER'POS('A');`{@:^LI := CHARACTER'POS('A');`{}b[ 524B522]Which one of the following declarations is^illegal`?{{{@.1.@#type RATE is digits 6;{{@.2.@#type DISTANCE is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type CURRENT is delta 0.1;{{@.4.@#type TEMP is delta 0.05 range -200.0 .. 450.0;{}Please press 1, 2, 3, or 4, or B to go back.[3525152625274528B523]@.1.@#type RATE is digits 6;{{@.2.@#type DISTANCE is digits 6 range 0.0 .. 1.0E6;{{@-^3.@#type CURRENT is delta 0.1;`{{@.4.@#type TEMP is delta 0.05 range -200.0 .. 450.0;{{{%You're right!~ A fixed point type declaration must have a range constraint.{}q[ 529B524Q524]@.1.@#type RATE is digits 6;{{@.2.@#type DISTANCE is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type CURRENT is delta 0.1;{{@.4.@#type TEMP is delta 0.05 range -200.0 .. 450.0;{{{No, number 1 is legal.  A user defined floating point type need not have a{range constraint.{}q[ 529B524Q524]@.1.@#type RATE is digits 6;{{@.2.@#type DISTANCE is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type CURRENT is delta 0.1;{{@.4.@#type TEMP is delta 0.05 range -200.0 .. 450.0;{{{No, number 2 is legal.  A user defined floating point type may have a range{constraint.{}q[ 529B524Q524]@.1.@#type RATE is digits 6;{{@.2.@#type DISTANCE is digits 6 range 0.0 .. 1.0E6;{{@.3.@#type CURRENT is delta 0.1;{{@.4.@#type TEMP is delta 0.05 range -200.0 .. 450.0;{{{No, number 4 is legal.  A fixed point type declaration must have a range{constraint.{}q[ 529B524Q524]@@MORE ATTRIBUTES{{Ada provides a wide variety of attributes.  All of them are listed and defined{in Appendix A of the LRM.  The most important ones that we haven't yet{discussed are these:{{%FIRST~and^LAST~can be used with any scalar type or subtype (including floating{and fixed), not just discrete types and subtypes.  For example,^FLOAT'LAST~is{the highest number your particular Ada represents with type FLOAT.{{For any real type or subtype (floating or fixed),^SMALL~and^LARGE~are the{smallest and largest positive model numbers.  Thus^FLOAT'SMALL~is the{difference between zero and the next larger number in type FLOAT.  Also, for{any floating point (sub)type,^EPSILON~is the difference between^one~and the{next larger number.  We'll use^EPSILON~in a generic function later.{{For a floating point (sub)type,^DIGITS~returns the value given for^digits~in{the declaration, and for a fixed point (sub)type,^DELTA~returns the value given{for^delta~in the declaration.  These attributes may not seem too useful,{because the programmer already knows what he wrote in the declarations.{However, they're useful in generic packages and subprograms.  For example, if{the generic part says^type DUMMY is delta <>;`, the body can use^DUMMY'DELTA`.{}b[ 530B524]For any discrete (sub)type,^WIDTH~gives the maximum length that the attribute{%IMAGE~can produce. ^BOOLEAN'WIDTH~is 5 because "FALSE" has length 5.  With our{earlier definition of RAINBOW_COLOR,^RAINBOW_COLOR'WIDTH~is 6.  For versions of{Ada using 16-bit INTEGERs,^INTEGER'WIDTH~is also 6, the length of "-32768".{{%COUNT~is used with the name of a task entry.  It returns the number of calls{presently queued on the entry. ^TERMINATED~is of type BOOLEAN.  It's used with{a task name, and tells if the task is terminated.{{Let's write a generic function to compute the square root for any floating{point type, using Newton-Raphson iteration.  This method simply says that if G{is a guess of the square root of X, the next guess is the average of G and X/G.{For example, if we want to compute the square root of 9.0 and our first guess{is 9.0, successive guesses are 5.0, 3.4, 3.02352941, 3.00009155, 3.00000000.{Note that convergence is very rapid.  However, the problem in writing a program{like this is knowing when to stop the iteration.  We'll use the attribute{%EPSILON`.  Since G*G/X should be 1.0, we'll quit when the absolute value of the{difference between G*G/X and 1.0 is less than or equal to 3.0 times EPSILON.{Recall that^DUMMY'EPSILON~is the difference between 1.0 and the next higher{number for type DUMMY.  If we use 1.0 times EPSILON, the loop might never{terminate, and if we use 10.0 times EPSILON, we might not get full precision.{So we'll use 3.0 times EPSILON.  Here's our function:{}b[ 531B529] ^generic`{@$^type DUMMY is digits <>;`{ ^function SQRT(X :in DUMMY) return DUMMY;`{ ^function SQRT(X :in DUMMY) return DUMMY is`{@$^GUESS : DUMMY := X;`{ ^begin`{@$^if X < 0.0 then`{@'^raise CONSTRAINT_ERROR;`{@$^end if;`{@$^while X /= 0.0 and then abs(GUESS*GUESS/X - 1.0) > 3.0*DUMMY'EPSILON loop`{@'^GUESS := (X/GUESS + GUESS) * 0.5;`{@$^end loop;`{@$^return GUESS;`{ ^end SQRT;`{{We tested our SQRT with an implementation of Ada having types FLOAT,{LONG_FLOAT, and LONG_LONG_FLOAT.  The last gives at least 33 decimal digits of{precision.  SQRT was instantiated for all three floating point types, as was{FLOAT_IO to display the results.  When tested with the three types, all{displayed digits of the answers were correct.{}b[ 532B530]@:SEQUENTIAL_IO AND DIRECT_IO{{TEXT_IO creates, reads and writes text files that can be typed on the screen or{printed.  Ada also provides packages^SEQUENTIAL_IO~and^DIRECT_IO,~which create,{read, and write binary files.  These files usually can't be typed or printed,{but they tend to be more efficient than text files, because the computer{doesn't have to convert numbers between its internal representation and ASCII{to read and write binary files.{{SEQUENTIAL_IO and DIRECT_IO are both generic, and can be instantiated for any{type.  The specifications are in sections 14.2.3 and 14.2.5 of the LRM.  Like{TEXT_IO, they have procedures to CREATE, OPEN, and CLOSE files, but the I/O{procedures are called READ and WRITE, rather than PUT, GET, PUT_LINE, and{GET_LINE.  SEQUENTIAL_IO always reads and writes sequentially, but DIRECT_IO is{capable of random access.  In DIRECT_IO, an optional extra parameter in READ{and WRITE tells the procedure the position in the file to read FROM or write{TO.{{TEXT_IO and instantiations of SEQUENTIAL_IO and DIRECT_IO each define their^own`{FILE_TYPE, so we can't open a file with one package and then do I/O with{another.  DIRECT_IO provides a FILE_MODE of INOUT_FILE as well as the usual{IN_FILE and OUT_FILE.{}b[ 533B531]If you like, you can examine the file ADA_TUTR.ADA for an example of the use of{DIRECT_IO. ^ADA-TUTR~creates a subtype for a block of characters and then{instantiates DIRECT_IO for that subtype.  It then opens ADA_TUTR.DAT with mode{IN_FILE so that it can read blocks of characters by random access.  This{enables^ADA-TUTR~to find and display any screen quickly.  The preliminary{comments in ADA_TUTR.ADA describe the format of the data file ADA_TUTR.DAT in{detail.{{You may also want to examine the files DAT2TXT.ADA and TXT2DAT.ADA.  These two{programs are used when installing^ADA-TUTR~on non-PC computers.  Their use is{described on pages 43-44 of your printed course notes.  They^with~both TEXT_IO{and DIRECT_IO, because they access a text file as well as a random access file.{However, to avoid confusion between the two packages, they^use~neither TEXT_IO{nor the instantiation of DIRECT_IO.  Dot notation is used instead.{}b[ 534B532]Which commented line is^illegal`?{{@$with TEXT_IO, SEQUENTIAL_IO; use TEXT_IO, SEQUENTIAL_IO; ^-- 1`{@$procedure IO is{@'subtype LINE is STRING(1 .. 80);{@'type SCREEN is array(1 .. 24) of LINE;{@'package LINE_IO is new SEQUENTIAL_IO(LINE); use LINE_IO; ^-- 2`{@'package SCREEN_IO is new SEQUENTIAL_IO(SCREEN); use SCREEN_IO; ^-- 3`{@$begin{@'null;{@$end IO;{}Please press 1, 2, or 3, or B to go back.[153525363537B533]@#^with TEXT_IO, SEQUENTIAL_IO; use TEXT_IO, SEQUENTIAL_IO;  -- 1`{@$procedure IO is{@'subtype LINE is STRING(1 .. 80);{@'type SCREEN is array(1 .. 24) of LINE;{@'package LINE_IO is new SEQUENTIAL_IO(LINE); use LINE_IO;  -- 2{@'package SCREEN_IO is new SEQUENTIAL_IO(SCREEN); use SCREEN_IO;  -- 3{@$begin{@'null;{@$end IO;{{%You're right!~ We can't^use~a generic package, only its instantiations,{because we can't call the subprograms in a generic package.  The first line{should read{{@/^with TEXT_IO, SEQUENTIAL_IO; use TEXT_IO;  -- 1`{}q[ 538B534Q534]@$with TEXT_IO, SEQUENTIAL_IO; use TEXT_IO, SEQUENTIAL_IO;  -- 1{@$procedure IO is{@'subtype LINE is STRING(1 .. 80);{@'type SCREEN is array(1 .. 24) of LINE;{@'package LINE_IO is new SEQUENTIAL_IO(LINE); use LINE_IO;  -- 2{@'package SCREEN_IO is new SEQUENTIAL_IO(SCREEN); use SCREEN_IO;  -- 3{@$begin{@'null;{@$end IO;{{No, the instantiation of SEQUENTIAL_IO for the subtype LINE is correct.{}q[ 538B534Q534]@$with TEXT_IO, SEQUENTIAL_IO; use TEXT_IO, SEQUENTIAL_IO;  -- 1{@$procedure IO is{@'subtype LINE is STRING(1 .. 80);{@'type SCREEN is array(1 .. 24) of LINE;{@'package LINE_IO is new SEQUENTIAL_IO(LINE); use LINE_IO;  -- 2{@'package SCREEN_IO is new SEQUENTIAL_IO(SCREEN); use SCREEN_IO;  -- 3{@$begin{@'null;{@$end IO;{{No, the instantiation of SEQUENTIAL_IO for the type SCREEN is correct.{}q[ 538B534Q534]@6SUBPROGRAM PARAMETERS WITH GENERICS{{The generic part of a subprogram or package can specify a dummy^subprogram~as{well as a dummy^type`.  This is similar to using subprograms as parameters{in Algol and Pascal, and to using the little-known keyword EXTERNAL in Fortran.{In Ada, we simply precede the dummy subprogram specification with the keyword{%with~in the generic part.  This use of the word^with~has nothing to do with{context clauses.  Here's the specification of a generic function that has one{dummy function specification in the generic part:{{^generic`{@#^with function DUMMY(X : in FLOAT) return FLOAT;`{^function DEFINITE_INTEGRAL(LOWER_LIMIT, UPPER_LIMIT : in FLOAT) return FLOAT;`{{We could then write a function COS, instantiate DEFINITE_INTEGRAL for it, and{use the instantiation as follows:{{^ANSWER : FLOAT;`{^function COS(X : in FLOAT) return FLOAT;`{^function DEFINITE_INTEGRAL_OF_COS is new DEFINITE_INTEGRAL(COS);`{ ...{^ANSWER := DEFINITE_INTEGRAL_OF_COS(LOWER_LIMIT => 0.0, UPPER_LIMIT => 1.5708);`{}b[ 539B534]generic{  ^with function DUMMY(X : in FLOAT) return FLOAT;`{function DEFINITE_INTEGRAL(LOWER_LIMIT, UPPER_LIMIT : in FLOAT) return FLOAT;{{function DEFINITE_INTEGRAL(LOWER_LIMIT, UPPER_LIMIT : in FLOAT) return FLOAT is{@#MULT : array(0 .. 6) of FLOAT := (1.0, 4.0, 2.0, 4.0, 2.0, 4.0, 1.0);{@#SUM  : FLOAT := 0.0;{@#X@$: FLOAT;  -- the independent variable{begin{@#for I in 0 .. 6 loop{@&X@#:= LOWER_LIMIT + (FLOAT(I) / 6.0) * (UPPER_LIMIT - LOWER_LIMIT);{@&SUM := SUM + MULT(I) *^DUMMY(X)`;{@#end loop;{@#return SUM * (UPPER_LIMIT - LOWER_LIMIT) / 18.0;{end DEFINITE_INTEGRAL;{{This is one possible body for the generic function DEFINITE_INTEGRAL.  (The{specification is repeated for reference.)  This function integrates the{function DUMMY between the two limits by evaluating DUMMY at seven points and{using Simpson's rule.  (DEFINITE_INTEGRAL could be improved by making the{number of points a generic parameter, instead of fixing it at seven.){}b[ 540B538]@7REPRESENTATION CLAUSES AND SYSTEM{{Ada normally represents an enumeration type internally with successive integers{starting at zero.  For example, if we write{{@0^type COMMAND is (LEFT, RIGHT, FORWARD, BACK);`{{the compiler will normally represent LEFT with 0, RIGHT with 1, etc.  Usually{this doesn't concern the programmer.  However, after the above declaration, we{can specify the internal representation with a^representation clause~like this:{{@&^for COMMAND use (LEFT => 1, RIGHT => 2, FORWARD => 4, BACK => 8);`{{We might want to do that if, for example, we're sending a value of type COMMAND{to some hardware which will interpret the bit patterns.  The values must be{assigned in increasing order with no duplications, but gaps are permitted.  The{attributes SUCC, PRED, POS, and VAL are^not~affected.  Thus^COMMAND'POS(BACK)`{is still 3.{{We can specify the^SIZE`, in bits, of the objects of a given type:{}b[ 541B539]@9^type NUM is range 0 .. 100;`{@9^for NUM'SIZE use 8;`{{We can specify the^STORAGE_SIZE~for a task type and for a collection of{%access`ed objects like a linked list.  If^MONITOR~is a task and the{specification for our linked list says^type P is access LINK;`, we can write{{@5^for MONITOR'STORAGE_SIZE use 16_384;`{@5^for P'STORAGE_SIZE use 32_768;`{{The attributes SIZE and STORAGE_SIZE can also be used in the usual way:{{@5^I : INTEGER := MONITOR'STORAGE_SIZE;`{{We can specify the attribute SMALL for a fixed point type:{{@/^type VOLTAGE is delta 0.01 range -20.0 .. 20.0;`{@/^for VOLTAGE'SMALL use 1.0/128.0;`{{Before discussing the remaining types of representation clauses, we must{briefly mention the package^SYSTEM~that comes with Ada. ^SYSTEM~contains{implementation dependent specifications.{}b[ 542B540]A brief outline of package SYSTEM is in section 13.7 of the LRM.  However, the{full package specification should appear in the documentation that came with{your compiler.  For all compilers that meet the Ada Standard, the description{of implementation dependent features (including the specification of package{SYSTEM) is always in Appendix F of the documentation.  Of interest here is the{type ADDRESS.  In our examples, we'll assume that SYSTEM.ADDRESS is some{integer type.  (Under DOS, type SYSTEM.ADDRESS may be a bit more complicated.){{Representation clauses can use the reserved word^at~followed by a constant of{type SYSTEM.ADDRESS to specify the absolute address of a variable, a constant,{a task entry, a procedure, or a package.  The package SYSTEM must be visible.{This feature is useful for memory-mapped I/O and interrupt handlers, etc.  For{example:{{@5MODEM_CONTROL : INTEGER;{@4^for MODEM_CONTROL use at 16#7C00#;`{@5task INTERRUPT_HANDLER is{@8entry CLOCK_INTERRUPT;{@7^for CLOCK_INTERRUPT use at 16#100#;`{@5end INTERRUPT_HANDLER;{@5procedure KEYSTROKE;{@4^for KEYSTROKE use at 16#200#;`{}b[ 543B541]Finally, we can use^at`,^mod`, and^range~to specify how records are stored.{For example,{{@3type VERY_SHORT_INTEGER is range 0 .. 15;{@3type PACKED is{@6record{@9A, B, C, D : VERY_SHORT_INTEGER;{@6end record;{@2^for PACKED use`{@5^record at mod 2;`{@8^A at 0 range 0 .. 3;`{@8^B at 0 range 4 .. 7;`{@8^C at 1 range 0 .. 3;`{@8^D at 1 range 4 .. 7;`{@5^end record;`{{This forces A and B to be stored in bits 0 .. 3 and 4 .. 7 of byte 0 of the{record, and C and D to be packed into byte 1.  The optional clause^record at{mod 2;~specifies that all records of type PACKED will begin at even addresses.{{An implementation of Ada need not accept most representation clauses to meet{the standard.  If any clause is rejected, an error message will be displayed.{}b[ 544B542]@0type ANSWER is (YES, NO, MAYBE);{@0for ANSWER use (YES => 1, NO => 2, MAYBE => 4);{{What is ANSWER'VAL(2)?{{{1.  ANSWER'VAL(2) is NO.{{2.  ANSWER'VAL(2) is MAYBE.{}Please press 1 or 2, or B to go back.[25451546B543]@/^type ANSWER is (YES, NO, MAYBE);`{@0for ANSWER use (YES => 1, NO => 2, MAYBE => 4);{{{%You're right!~ The representation clause doesn't affect the attributes POS and{VAL, and positions are numbered from zero.  So^ANSWER'VAL(2)~is^MAYBE`.{}q[ 547B544Q544]@0type ANSWER is (YES, NO, MAYBE);{@0for ANSWER use (YES => 1, NO => 2, MAYBE => 4);{{{No, the representation clause doesn't affect the attributes POS and VAL, and{positions are numbered from zero.  So ANSWER'VAL(2) is MAYBE.{}q[ 547B544Q544]@0UNCHECKED CONVERSION AND UNCHECKED DEALLOCATION{{Ada comes with a generic function^UNCHECKED_CONVERSION~and a generic procedure{%UNCHECKED_DEALLOCATION`.  They can be instantiated for any type.  Both are{somewhat dangerous to use, but we'll describe them briefly.  Their{specifications are:{{@+^generic`{@.^type SOURCE is limited private;`{@.^type TARGET is limited private;`{@+^function UNCHECKED_CONVERSION(S : SOURCE) return TARGET;`{{@+^generic`{@.^type OBJECT is limited private;`{@.^type NAME@#is access OBJECT;`{@+^procedure UNCHECKED_DEALLOCATION(X : in out NAME);`{{UNCHECKED_CONVERSION "converts" from one type to another without doing any{arithmetic or bit manipulation.  In other words, it lets us look at an object{of one type as if it were of another type.  The effect is similar to the use{of EQUIVALENCE in Fortran.  The results may be unpredictable unless the two{types occupy the same amount of storage.{}b[ 548B544]One use of UNCHECKED_CONVERSION might be to allow us to^and~two INTEGERs.  Some{Ada compilers come with a package that enables us to do that, but many{compilers have no such package.  Suppose that types INTEGER and BOOLEAN occupy{the same amount of storage.  If our program says^with UNCHECKED_CONVERSION;~we{could write{{@%^function INT_TO_BOOL is new UNCHECKED_CONVERSION(INTEGER, BOOLEAN);`{@%^function BOOL_TO_INT is new UNCHECKED_CONVERSION(BOOLEAN, INTEGER);`{@%^function "and"(LEFT, RIGHT : in INTEGER) return INTEGER is`{@%^begin`{@(^return BOOL_TO_INT(INT_TO_BOOL(LEFT) and INT_TO_BOOL(RIGHT));`{@%^end "and";`{{Using UNCHECKED_CONVERSION usually destroys program portability.{{UNCHECKED_DEALLOCATION allows us to free the memory occupied by an object{associated with a pointer.  Normally, the system reclaims memory when it's{needed.  However, the execution time for that so-called^garbage collection`{tends to be long and unpredictable.  Suppose we have^type P is access LINK;~and{%HEAD : P;`.  Also suppose that we no longer need the object pointed to by HEAD`,{and we're sure that no other pointer points to the same object as HEAD.  If our{program says^with UNCHECKED_DEALLOCATION;~we can write{}b[ 549B547]@,^procedure FREE is new UNCHECKED_DEALLOCATION(LINK, P);`{@-...{@,^FREE(HEAD);`{{This will release the memory occupied by the object pointed to by^HEAD`, and{then set^HEAD~to^null`.  But there's a danger.  If there's another pointer that{pointed to the same object, it now points to released memory.  A reference to{that pointer will have unpredictable results.  In general, it's best to let the{system handle the reclaiming of memory.  That way there's no danger of dangling{references.{}b[ 550B548]@DPRAGMAS{{A^pragma~is a message to the compiler.  The pragmas that are predefined by Ada{are all described in Appendix B of the LRM; we'll discuss the most important{ones here.  A particular implementation of Ada need not honor all the{predefined pragmas, and it may add some of its own.  (One implementation of Ada{adds a pragma TIME_SLICE, used with tasking.)  Unlike representation clauses,{unimplemented predefined pragmas do^not~cause error messages; the compiler{simply ignores them.  This enhances program portability.  Any additional{pragmas added by a particular implementation of Ada will be explained in{Appendix F of the compiler documentation.  The most important predefined{pragmas are these:{{The statements^pragma LIST(ON);~and^pragma LIST(OFF);~turn on and off the{compiler listing.  Also,^pragma PAGE;~will cause the compiler listing to start{a new page, if the listing is turned on.  These pragmas are allowed almost{anywhere in the program.{{Within the declarative region we can write^pragma OPTIMIZE(TIME);~or^pragma{OPTIMIZE(SPACE);~to ask the compiler to optimize the program for minimum{execution time or minimum memory usage.{}b[ 551B549]We can write^pragma INLINE(`...%);~with the name of a subprogram to ask the{compiler to write inline code in place of every call to the subprogram.  Even{implementations of Ada that honor this pragma will ignore it if the subprogram{is recursive.{{We can interface a subprogram written in another language by writing^pragma{INTERFACE(`...%,~...%);~after the subprogram specification.  The two arguments are{the name of the language and the subprogram name.  Consult the compiler{documentation for information on bringing the object file into the Ada library.{{We can ask the compiler to minimize memory occupied by a record or array by{writing, after the type declaration,^pragma PACK(`...%);~with the name of the{type.  Note that the specification for package STANDARD (in Appendix C of the{LRM) contains^pragma PACK(STRING);~after the definition of type STRING.{{Package SYSTEM defines a subtype of INTEGER called PRIORITY.  We can assign a{priority to a task by writing, in the specification,^pragma PRIORITY(`...%);~with{an argument of subtype SYSTEM.PRIORITY.  Higher numbers denote greater urgency.{{The pragma^SUPPRESS~can be used to ask the compiler to turn off certain checks,{such as CONSTRAINT_ERROR.  It's dangerous and shouldn't be used unless{absolutely necessary because of time or memory constraints.{}b[ 552B550]In the author's opinion, which one of these is^not~dangerous?{{{@61.  UNCHECKED_DEALLOCATION{{@62.  pragma PACK{{@63.  pragma SUPPRESS{}Please press 1, 2, or 3, or B to go back.[255315543555B551]@61.  UNCHECKED_DEALLOCATION{{@5^2.  pragma PACK`{{@63.  pragma SUPPRESS{{{%You're right!~ The worst^pragma PACK~could do is slow the program down, and{this pragma is used in package STANDARD.  UNCHECKED_DEALLOCATION could allow a{pointer to point to memory that has been released, with unpredictable results.{Pragma SUPPRESS could allow a program to use a subscript that's out of range,{etc.{}q[ 556B552Q552]@61.  UNCHECKED_DEALLOCATION{{@62.  pragma PACK{{@63.  pragma SUPPRESS{{{No, UNCHECKED_DEALLOCATION is dangerous because it could allow a pointer to{point to memory that has been released, with unpredictable results.{}q[ 556B552Q552]@61.  UNCHECKED_DEALLOCATION{{@62.  pragma PACK{{@63.  pragma SUPPRESS{{{No, pragma SUPPRESS is dangerous because it could allow a program to use a{subscript that's out of range, etc.{}q[ 556B552Q552]@<LOOSE ENDS AND PITFALLS{{In this final section, we cover some miscellaneous topics that were omitted{earlier for simplicity.  We also mention some common errors made by Ada{programmers.  Beginners aren't expected to understand every paragraph until{they've gained more experience, and we won't ask questions in this section.{{Some terminals and printers don't support the entire ASCII character set.  In{an Ada program, the vertical bar^|~may be replaced with the exclamation mark^!`,{as in^when 3 ! 5 =>`.  Also, a pair of sharp signs^#~may be replaced with a pair{of colons^:`, as in^16:7C03:`.  The quotation marks around a string constant may{be replaced with percent signs if the string doesn't contain any quotation{marks.  In that case, any percent signs within the string must be doubled.{These character replacements shouldn't be used in programs if the equipment{will support the standard characters.{{An expression is called^static~if it can be evaluated at compile time.  In{almost every case where a constant normally appears, a static expression may{also be used.  For example, an address representation clause normally takes{a constant of type SYSTEM.ADDRESS.  A static expression of this type is also{acceptable, as in^for CLOCK_INTERRUPT use at 16*16;`.{}b[ 557B552]The unary minus is always an operator and never part of a constant.  Thus^-5`{is actually a static expression and not a constant.  Normally, this doesn't{concern the programmer, because, as we just said, static expressions can{usually appear where a constant appears.  However, in a few special situations{we can get into trouble.  For example, we can write^for I in 10 .. 20 loop~and{%A : array(10 .. 20) of FLOAT;~but we can't omit the words^INTEGER range~in{%for I in INTEGER range -10 .. 10 loop~and^A : array(INTEGER range -10 .. 10) of{FLOAT;`!  Also, if a package P declares^type COUNT is new INTEGER;~then the{unary minus operator for that type is part of the package.  If our program{%with`s but doesn't^use~P, we can write^A : P.COUNT := 1;~but not{%B : P.COUNT := -1;`.  We either have to^use~the package,^rename~P."-", or write{%B : P.COUNT := P."-"(1);`.{{The operators have precedence, so that 1 + 2 * 3 means 1 + (2 * 3).  The{precedence of all the operators is given in section 4.5 of the LRM.  A{programmer should never have to look these up, because parentheses should be{used for any cases that aren't obvious.  Unary minus has a low precedence, so{%-A mod B~means^-(A mod B)`.{{If we write^A, B : array(1 .. 5) of FLOAT;~then A and B have^different`{anonymous types, and we can't write^A := B;`.  To fix this, write{%type VECTOR5 is array(1 .. 5) of FLOAT;~and then^A, B : VECTOR5;`.{}b[ 558B556]Ada will automatically convert from a universal type to a named type, but not{from a named type to a universal.  For example,{{@3^C1 : constant INTEGER := 1;  -- legal`{@3^C2 : constant INTEGER := 2;  -- legal`{@3^C3 : constant := C1 + C2;@$-- illegal`{{When arrays are assigned, the subscripts don't have to match; only the lengths{and types need match.  But if a formal parameter ("dummy argument") of a{subprogram is a constrained array, the subscripts in the call to the subprogram{must match.  For example, the last line here will raise CONSTRAINT_ERROR:{{@5^subtype NAME is STRING(1 .. 30);`{@5^JOHN : NAME;`{@5^LINE : STRING(1 .. 80);`{@5^procedure DISPLAY(PERSON : in NAME);`{@6...{@5^JOHN := LINE(51 .. 80);@#-- legal`{@5^DISPLAY(LINE( 1 .. 30));  -- legal`{@5^DISPLAY(LINE(51 .. 80));  -- illegal`{}b[ 559B557]When a subprogram formal parameter is an^un`constrained array, beginners often{wrongly assume that the subscripts will start with one.  For example,{{@5^LINE : STRING(1 .. 80);`{@5^procedure DISPLAY(S : in STRING) is`{@5^begin`{@8^for I in 1 .. S'LENGTH loop`{@<...^S(I)~...{{This will raise CONSTRAINT_ERROR if we call^DISPLAY(LINE(51 .. 80));`.  The^for`{statement should be changed to say^for I in S'RANGE loop`.{{Remember that elaboration occurs at run time.  The following raises{PROGRAM_ERROR by trying to activate a task before elaborating its body:{{@:^task type T is~...^end T;`{@:^type P is access T;`{@:^T1 : P := new T;`{@:^task body T is~...^end T;`{{The third line should be changed to^T1 : P;~and the statement^T1 := new T;`{should be placed in the executable region.{}b[ 560B558]Similarly, this procedure tries to activate a function before elaborating its{body.  The initialization of J should be moved to the executable region:{{@0^procedure TEST is`{@3^function X return INTEGER;`{@3^J : INTEGER := X;  -- Raises PROGRAM_ERROR.`{@3^function X return INTEGER is`{@3^begin`{@6^return 5;`{@3^end X;`{@0^begin`{@3^null;`{@0^end TEST;`{{A^return~statement in a function is used with an object:^return ANSWER;`.{However,^return~may also appear without an object in a^procedure`; we simply{write^return;`.  Normally, a procedure returns after executing its last{statement, but an early return is possible by this method.  Well structured{programs don't use this feature of Ada.{}b[ 561B559]Some implementations of Ada provide a package^LOW_LEVEL_IO~which includes{overloaded procedures^SEND_CONTROL~and^RECEIVE_CONTROL~to interface various{hardware devices directly.  This package is completely implementation{dependent, so you'll have to consult Appendix F of your compiler documentation.{{Many implementations of Ada allow you to insert^machine code~into a program.{Some implementations do this with a pragma, such as^pragma NATIVE`, which can be{inserted in the middle of a procedure, function, etc.  Other implementations{provide a package called^MACHINE_CODE~which usually contains a rather complex{record definition representing the format of a machine instruction.  In this{case, we can write a procedure or function that^with`s MACHINE_CODE.  In place{of the usual Ada statements in the executable region, we write record{aggregates, each one representing a machine code instruction.  Since the method{of inserting machine code into a program varies from one implementation to the{next, you'll have to consult the compiler documentation.{}b[ 562B560]In the unusual case of a^for~loop index hiding an explicitly declared object of{the same name, the explicitly declared object^can~be referenced inside the{loop.  Simply use dot notation with the name of the compilation unit (function,{procedure, etc.)  For example, the following is legal:{{@;procedure MAIN is{@>IX : FLOAT;{@>J  : INTEGER;{@;begin{@>IX := 3.2;{@>for IX in 1 .. 10 loop{@@^MAIN.IX~:= 6.0;{@AJ := IX;{@>end loop;{@;end MAIN;{{%Inside~the loop,^IX~refers to the loop index, and the explicitly declared{object can be referenceed by writing^MAIN.IX`. ^Outside~the loop,^IX~refers to{the explicitly declared object, and the loop index doesn't exist.{}b[ 563B561]In the rare case of an aggregate containing just one element, we must use named{notation rather than positional notation.  For example, the last line is{illegal in the following program segment, because the right hand side is a{FLOAT rather than an array of one FLOAT.{{@0type VECTOR is array(INTEGER range <>) of FLOAT;{@/^A : VECTOR(1 .. 1);`{@0...{@/^A := (1 => 2.3);  -- legal`{@/^A := (2.3);  -- illegal`{{It's OK to use positional notation in calls to subprograms with only one{parameter, for example,^PUT_LINE("Hello");`.{}b[ 564B562]Well, we haven't covered^all~there is to know about Ada, but this has been a{very thorough course.  If you've come this far and completed the six Outside{Assignments, you should be a very good Ada programmer.  To be an excellent Ada{programmer, start doing all your casual programming in Ada.  If you need a{simple program to balance your checkbook, write it in Ada!  At this point,{switching to Ada for all your programming will do you much more good than{further instruction from a tutorial program.{{The best way to answer any remaining questions about Ada is to "ask the{compiler" by writing a brief test program, especially if your compiler is{validated.  You can also look in the LRM, which, by definition, does cover^all`{of the Ada language.  However, the LRM isn't easy reading!{{The best way to debug a short program is often to execute it by hand, with{pencil and paper.  You can also add extra statements to the program to display{intermediate results, and remove them later.{{We wish you success with Ada, and welcome your comments and suggestions!{{Now, you can press B to go back,{{@2or, for one last time ...{}@:... type a space to go on.[ 101B563]